diff options
Diffstat (limited to 'drivers')
241 files changed, 12229 insertions, 5868 deletions
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 5152bd1b0daf..61e5c607a72f 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -560,9 +560,9 @@ void dpll_pin_put(struct dpll_pin *pin) { mutex_lock(&dpll_lock); if (refcount_dec_and_test(&pin->refcount)) { + xa_erase(&dpll_pin_xa, pin->id); xa_destroy(&pin->dpll_refs); xa_destroy(&pin->parent_refs); - xa_erase(&dpll_pin_xa, pin->id); dpll_pin_prop_free(&pin->prop); kfree(pin); } diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 314bb3775465..cf3313517ae1 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -121,14 +121,21 @@ dpll_msg_add_lock_status(struct sk_buff *msg, struct dpll_device *dpll, struct netlink_ext_ack *extack) { const struct dpll_device_ops *ops = dpll_device_ops(dpll); + enum dpll_lock_status_error status_error = 0; enum dpll_lock_status status; int ret; - ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, extack); + ret = ops->lock_status_get(dpll, dpll_priv(dpll), &status, + &status_error, extack); if (ret) return ret; if (nla_put_u32(msg, DPLL_A_LOCK_STATUS, status)) return -EMSGSIZE; + if (status_error && + (status == DPLL_LOCK_STATUS_UNLOCKED || + status == DPLL_LOCK_STATUS_HOLDOVER) && + nla_put_u32(msg, DPLL_A_LOCK_STATUS_ERROR, status_error)) + return -EMSGSIZE; return 0; } diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c index fe17c7f98e81..6d07693c6b9f 100644 --- a/drivers/media/rc/bpf-lirc.c +++ b/drivers/media/rc/bpf-lirc.c @@ -110,7 +110,7 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_get_prandom_u32: return &bpf_get_prandom_u32_proto; case BPF_FUNC_trace_printk: - if (perfmon_capable()) + if (bpf_token_capable(prog->aux->token, CAP_PERFMON)) return bpf_get_trace_printk_proto(); fallthrough; default: diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index d9e052c49ba1..166bfc3c8e6c 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -108,6 +108,7 @@ static int go_tx(struct net_device *dev); static int debug = ARCNET_DEBUG; module_param(debug, int, 0); +MODULE_DESCRIPTION("ARCnet core driver"); MODULE_LICENSE("GPL"); static int __init arcnet_init(void) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index f8c1d73b251d..3092b391031a 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -48,7 +48,7 @@ config NET_DSA_MT7530 config NET_DSA_MT7530_MDIO tristate "MediaTek MT7530 MDIO interface driver" depends on NET_DSA_MT7530 - imply MEDIATEK_GE_PHY + select MEDIATEK_GE_PHY select PCS_MTK_LYNXI help This enables support for the MediaTek MT7530 and MT7531 switch diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 0d628b35fd5c..adc93abf4551 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1257,7 +1257,7 @@ static void b53_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phydev) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; u8 rgmii_ctrl = 0, reg = 0, off; bool tx_pause = false; bool rx_pause = false; @@ -2224,10 +2224,10 @@ int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy) } EXPORT_SYMBOL(b53_eee_init); -int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; u16 reg; if (is5325(dev) || is5365(dev)) @@ -2241,10 +2241,10 @@ int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) } EXPORT_SYMBOL(b53_get_mac_eee); -int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e) +int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e) { struct b53_device *dev = ds->priv; - struct ethtool_eee *p = &dev->ports[port].eee; + struct ethtool_keee *p = &dev->ports[port].eee; if (is5325(dev) || is5365(dev)) return -EOPNOTSUPP; diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index fdcfd5081c28..c26a03755e83 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -95,7 +95,7 @@ struct b53_pcs { struct b53_port { u16 vlan_ctl_mask; - struct ethtool_eee eee; + struct ethtool_keee eee; }; struct b53_vlan { @@ -397,7 +397,7 @@ void b53_disable_port(struct dsa_switch *ds, int port); void b53_brcm_hdr_setup(struct dsa_switch *ds, int port); void b53_eee_enable_set(struct dsa_switch *ds, int port, bool enable); int b53_eee_init(struct dsa_switch *ds, int port, struct phy_device *phy); -int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); -int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); +int b53_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); +int b53_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); #endif diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 4a52ccbe393f..bc77ee9e6d0a 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -835,7 +835,7 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, bool tx_pause, bool rx_pause) { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); - struct ethtool_eee *p = &priv->dev->ports[port].eee; + struct ethtool_keee *p = &priv->dev->ports[port].eee; u32 reg_rgmii_ctrl = 0; u32 reg, offset; diff --git a/drivers/net/dsa/microchip/ksz8795.c b/drivers/net/dsa/microchip/ksz8795.c index 61b71bcfe396..50351cef6ca5 100644 --- a/drivers/net/dsa/microchip/ksz8795.c +++ b/drivers/net/dsa/microchip/ksz8795.c @@ -633,6 +633,57 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan) } /** + * ksz879x_get_loopback - KSZ879x specific function to get loopback + * configuration status for a specific port + * @dev: Pointer to the device structure + * @port: Port number to query + * @val: Pointer to store the result + * + * This function reads the SMI registers to determine whether loopback mode + * is enabled for a specific port. + * + * Return: 0 on success, error code on failure. + */ +static int ksz879x_get_loopback(struct ksz_device *dev, u16 port, + u16 *val) +{ + u8 stat3; + int ret; + + ret = ksz_pread8(dev, port, REG_PORT_STATUS_3, &stat3); + if (ret) + return ret; + + if (stat3 & PORT_PHY_LOOPBACK) + *val |= BMCR_LOOPBACK; + + return 0; +} + +/** + * ksz879x_set_loopback - KSZ879x specific function to set loopback mode for + * a specific port + * @dev: Pointer to the device structure. + * @port: Port number to modify. + * @val: Value indicating whether to enable or disable loopback mode. + * + * This function translates loopback bit of the BMCR register into the + * corresponding hardware register bit value and writes it to the SMI interface. + * + * Return: 0 on success, error code on failure. + */ +static int ksz879x_set_loopback(struct ksz_device *dev, u16 port, u16 val) +{ + u8 stat3 = 0; + + if (val & BMCR_LOOPBACK) + stat3 |= PORT_PHY_LOOPBACK; + + return ksz_prmw8(dev, port, REG_PORT_STATUS_3, PORT_PHY_LOOPBACK, + stat3); +} + +/** * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY * Control register (Reg. 31). * @dev: The KSZ device instance. @@ -676,59 +727,122 @@ static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val) return 0; } +/** + * ksz8_r_phy_bmcr - Translates and reads from the SMI interface to a MIIM PHY + * Basic mode control register (Reg. 0). + * @dev: The KSZ device instance. + * @port: The port number to be read. + * @val: The value read from the SMI interface. + * + * This function reads the SMI interface and translates the hardware register + * bit values into their corresponding control settings for a MIIM PHY Basic + * mode control register. + * + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 + * ------------------------------------------------------------------- + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit + * ----------------------------+-----------------------------+---------------- + * Bit 15 - Soft Reset | 0xF/4 | Not supported + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 + * Bit 7 - Collision Test/Res. | Not supported | Not supported + * Bit 6 - Reserved | Not supported | Not supported + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 + * ------------------------------------------------------------------- + * + * Return: 0 on success, error code on failure. + */ +static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val) +{ + const u16 *regs = dev->info->regs; + u8 restart, speed, ctrl; + int ret; + + *val = 0; + + ret = ksz_pread8(dev, port, regs[P_NEG_RESTART_CTRL], &restart); + if (ret) + return ret; + + ret = ksz_pread8(dev, port, regs[P_SPEED_STATUS], &speed); + if (ret) + return ret; + + ret = ksz_pread8(dev, port, regs[P_FORCE_CTRL], &ctrl); + if (ret) + return ret; + + if (ctrl & PORT_FORCE_100_MBIT) + *val |= BMCR_SPEED100; + + if (ksz_is_ksz88x3(dev)) { + if (restart & KSZ8873_PORT_PHY_LOOPBACK) + *val |= BMCR_LOOPBACK; + + if ((ctrl & PORT_AUTO_NEG_ENABLE)) + *val |= BMCR_ANENABLE; + } else { + ret = ksz879x_get_loopback(dev, port, val); + if (ret) + return ret; + + if (!(ctrl & PORT_AUTO_NEG_DISABLE)) + *val |= BMCR_ANENABLE; + } + + if (restart & PORT_POWER_DOWN) + *val |= BMCR_PDOWN; + + if (restart & PORT_AUTO_NEG_RESTART) + *val |= BMCR_ANRESTART; + + if (ctrl & PORT_FORCE_FULL_DUPLEX) + *val |= BMCR_FULLDPLX; + + if (speed & PORT_HP_MDIX) + *val |= KSZ886X_BMCR_HP_MDIX; + + if (restart & PORT_FORCE_MDIX) + *val |= KSZ886X_BMCR_FORCE_MDI; + + if (restart & PORT_AUTO_MDIX_DISABLE) + *val |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; + + if (restart & PORT_TX_DISABLE) + *val |= KSZ886X_BMCR_DISABLE_TRANSMIT; + + if (restart & PORT_LED_OFF) + *val |= KSZ886X_BMCR_DISABLE_LED; + + return 0; +} + int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val) { - u8 restart, speed, ctrl, link; + u8 ctrl, link, val1, val2; int processed = true; const u16 *regs; - u8 val1, val2; u16 data = 0; - u8 p = phy; + u16 p = phy; int ret; regs = dev->info->regs; switch (reg) { case MII_BMCR: - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); - if (ret) - return ret; - - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); + ret = ksz8_r_phy_bmcr(dev, p, &data); if (ret) return ret; - - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); - if (ret) - return ret; - - if (restart & PORT_PHY_LOOPBACK) - data |= BMCR_LOOPBACK; - if (ctrl & PORT_FORCE_100_MBIT) - data |= BMCR_SPEED100; - if (ksz_is_ksz88x3(dev)) { - if ((ctrl & PORT_AUTO_NEG_ENABLE)) - data |= BMCR_ANENABLE; - } else { - if (!(ctrl & PORT_AUTO_NEG_DISABLE)) - data |= BMCR_ANENABLE; - } - if (restart & PORT_POWER_DOWN) - data |= BMCR_PDOWN; - if (restart & PORT_AUTO_NEG_RESTART) - data |= BMCR_ANRESTART; - if (ctrl & PORT_FORCE_FULL_DUPLEX) - data |= BMCR_FULLDPLX; - if (speed & PORT_HP_MDIX) - data |= KSZ886X_BMCR_HP_MDIX; - if (restart & PORT_FORCE_MDIX) - data |= KSZ886X_BMCR_FORCE_MDI; - if (restart & PORT_AUTO_MDIX_DISABLE) - data |= KSZ886X_BMCR_DISABLE_AUTO_MDIX; - if (restart & PORT_TX_DISABLE) - data |= KSZ886X_BMCR_DISABLE_TRANSMIT; - if (restart & PORT_LED_OFF) - data |= KSZ886X_BMCR_DISABLE_LED; break; case MII_BMSR: ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link); @@ -860,113 +974,137 @@ static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val) return ret; } -int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) +/** + * ksz8_w_phy_bmcr - Translates and writes to the SMI interface from a MIIM PHY + * Basic mode control register (Reg. 0). + * @dev: The KSZ device instance. + * @port: The port number to be configured. + * @val: The register value to be written. + * + * This function translates control settings from a MIIM PHY Basic mode control + * register into their corresponding hardware register bit values for the SMI + * interface. + * + * MIIM Bit Mapping Comparison between KSZ8794 and KSZ8873 + * ------------------------------------------------------------------- + * MIIM Bit | KSZ8794 Reg/Bit | KSZ8873 Reg/Bit + * ----------------------------+-----------------------------+---------------- + * Bit 15 - Soft Reset | 0xF/4 | Not supported + * Bit 14 - Loopback | 0xD/0 (MAC), 0xF/7 (PHY) ~ 0xD/0 (PHY) + * Bit 13 - Force 100 | 0xC/6 = 0xC/6 + * Bit 12 - AN Enable | 0xC/7 (reverse logic) ~ 0xC/7 + * Bit 11 - Power Down | 0xD/3 = 0xD/3 + * Bit 10 - PHY Isolate | 0xF/5 | Not supported + * Bit 9 - Restart AN | 0xD/5 = 0xD/5 + * Bit 8 - Force Full-Duplex | 0xC/5 = 0xC/5 + * Bit 7 - Collision Test/Res. | Not supported | Not supported + * Bit 6 - Reserved | Not supported | Not supported + * Bit 5 - Hp_mdix | 0x9/7 ~ 0xF/7 + * Bit 4 - Force MDI | 0xD/1 = 0xD/1 + * Bit 3 - Disable MDIX | 0xD/2 = 0xD/2 + * Bit 2 - Disable Far-End F. | ???? | 0xD/4 + * Bit 1 - Disable Transmit | 0xD/6 = 0xD/6 + * Bit 0 - Disable LED | 0xD/7 = 0xD/7 + * ------------------------------------------------------------------- + * + * Return: 0 on success, error code on failure. + */ +static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val) { - u8 restart, speed, ctrl, data; - const u16 *regs; - u8 p = phy; + u8 restart, speed, ctrl, restart_mask; + const u16 *regs = dev->info->regs; int ret; - regs = dev->info->regs; + /* Do not support PHY reset function. */ + if (val & BMCR_RESET) + return 0; - switch (reg) { - case MII_BMCR: + speed = 0; + if (val & KSZ886X_BMCR_HP_MDIX) + speed |= PORT_HP_MDIX; - /* Do not support PHY reset function. */ - if (val & BMCR_RESET) - break; - ret = ksz_pread8(dev, p, regs[P_SPEED_STATUS], &speed); - if (ret) - return ret; + ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed); + if (ret) + return ret; - data = speed; - if (val & KSZ886X_BMCR_HP_MDIX) - data |= PORT_HP_MDIX; - else - data &= ~PORT_HP_MDIX; + ctrl = 0; + if (ksz_is_ksz88x3(dev)) { + if ((val & BMCR_ANENABLE)) + ctrl |= PORT_AUTO_NEG_ENABLE; + } else { + if (!(val & BMCR_ANENABLE)) + ctrl |= PORT_AUTO_NEG_DISABLE; - if (data != speed) { - ret = ksz_pwrite8(dev, p, regs[P_SPEED_STATUS], data); - if (ret) - return ret; - } + /* Fiber port does not support auto-negotiation. */ + if (dev->ports[port].fiber) + ctrl |= PORT_AUTO_NEG_DISABLE; + } - ret = ksz_pread8(dev, p, regs[P_FORCE_CTRL], &ctrl); - if (ret) - return ret; + if (val & BMCR_SPEED100) + ctrl |= PORT_FORCE_100_MBIT; - data = ctrl; - if (ksz_is_ksz88x3(dev)) { - if ((val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_ENABLE; - else - data &= ~PORT_AUTO_NEG_ENABLE; - } else { - if (!(val & BMCR_ANENABLE)) - data |= PORT_AUTO_NEG_DISABLE; - else - data &= ~PORT_AUTO_NEG_DISABLE; - - /* Fiber port does not support auto-negotiation. */ - if (dev->ports[p].fiber) - data |= PORT_AUTO_NEG_DISABLE; - } + if (val & BMCR_FULLDPLX) + ctrl |= PORT_FORCE_FULL_DUPLEX; - if (val & BMCR_SPEED100) - data |= PORT_FORCE_100_MBIT; - else - data &= ~PORT_FORCE_100_MBIT; - if (val & BMCR_FULLDPLX) - data |= PORT_FORCE_FULL_DUPLEX; - else - data &= ~PORT_FORCE_FULL_DUPLEX; + ret = ksz_prmw8(dev, port, regs[P_FORCE_CTRL], PORT_FORCE_100_MBIT | + /* PORT_AUTO_NEG_ENABLE and PORT_AUTO_NEG_DISABLE are the same + * bits + */ + PORT_FORCE_FULL_DUPLEX | PORT_AUTO_NEG_ENABLE, ctrl); + if (ret) + return ret; - if (data != ctrl) { - ret = ksz_pwrite8(dev, p, regs[P_FORCE_CTRL], data); - if (ret) - return ret; - } + restart = 0; + restart_mask = PORT_LED_OFF | PORT_TX_DISABLE | PORT_AUTO_NEG_RESTART | + PORT_POWER_DOWN | PORT_AUTO_MDIX_DISABLE | PORT_FORCE_MDIX; + + if (val & KSZ886X_BMCR_DISABLE_LED) + restart |= PORT_LED_OFF; + + if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) + restart |= PORT_TX_DISABLE; + + if (val & BMCR_ANRESTART) + restart |= PORT_AUTO_NEG_RESTART; + + if (val & BMCR_PDOWN) + restart |= PORT_POWER_DOWN; + + if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) + restart |= PORT_AUTO_MDIX_DISABLE; + + if (val & KSZ886X_BMCR_FORCE_MDI) + restart |= PORT_FORCE_MDIX; - ret = ksz_pread8(dev, p, regs[P_NEG_RESTART_CTRL], &restart); + if (ksz_is_ksz88x3(dev)) { + restart_mask |= KSZ8873_PORT_PHY_LOOPBACK; + + if (val & BMCR_LOOPBACK) + restart |= KSZ8873_PORT_PHY_LOOPBACK; + } else { + ret = ksz879x_set_loopback(dev, port, val); if (ret) return ret; + } - data = restart; - if (val & KSZ886X_BMCR_DISABLE_LED) - data |= PORT_LED_OFF; - else - data &= ~PORT_LED_OFF; - if (val & KSZ886X_BMCR_DISABLE_TRANSMIT) - data |= PORT_TX_DISABLE; - else - data &= ~PORT_TX_DISABLE; - if (val & BMCR_ANRESTART) - data |= PORT_AUTO_NEG_RESTART; - else - data &= ~(PORT_AUTO_NEG_RESTART); - if (val & BMCR_PDOWN) - data |= PORT_POWER_DOWN; - else - data &= ~PORT_POWER_DOWN; - if (val & KSZ886X_BMCR_DISABLE_AUTO_MDIX) - data |= PORT_AUTO_MDIX_DISABLE; - else - data &= ~PORT_AUTO_MDIX_DISABLE; - if (val & KSZ886X_BMCR_FORCE_MDI) - data |= PORT_FORCE_MDIX; - else - data &= ~PORT_FORCE_MDIX; - if (val & BMCR_LOOPBACK) - data |= PORT_PHY_LOOPBACK; - else - data &= ~PORT_PHY_LOOPBACK; + return ksz_prmw8(dev, port, regs[P_NEG_RESTART_CTRL], restart_mask, + restart); +} - if (data != restart) { - ret = ksz_pwrite8(dev, p, regs[P_NEG_RESTART_CTRL], - data); - if (ret) - return ret; - } +int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val) +{ + const u16 *regs; + u8 ctrl, data; + u16 p = phy; + int ret; + + regs = dev->info->regs; + + switch (reg) { + case MII_BMCR: + ret = ksz8_w_phy_bmcr(dev, p, val); + if (ret) + return ret; break; case MII_ADVERTISE: ret = ksz_pread8(dev, p, regs[P_LOCAL_CTRL], &ctrl); diff --git a/drivers/net/dsa/microchip/ksz8795_reg.h b/drivers/net/dsa/microchip/ksz8795_reg.h index beca974e0171..7c9341ef73b0 100644 --- a/drivers/net/dsa/microchip/ksz8795_reg.h +++ b/drivers/net/dsa/microchip/ksz8795_reg.h @@ -265,6 +265,7 @@ #define PORT_AUTO_MDIX_DISABLE BIT(2) #define PORT_FORCE_MDIX BIT(1) #define PORT_MAC_LOOPBACK BIT(0) +#define KSZ8873_PORT_PHY_LOOPBACK BIT(0) #define REG_PORT_1_STATUS_2 0x1E #define REG_PORT_2_STATUS_2 0x2E diff --git a/drivers/net/dsa/microchip/ksz9477_i2c.c b/drivers/net/dsa/microchip/ksz9477_i2c.c index cac4a607e54a..82bebee4615c 100644 --- a/drivers/net/dsa/microchip/ksz9477_i2c.c +++ b/drivers/net/dsa/microchip/ksz9477_i2c.c @@ -104,6 +104,10 @@ static const struct of_device_id ksz9477_dt_ids[] = { .data = &ksz_switch_chips[KSZ8563] }, { + .compatible = "microchip,ksz8567", + .data = &ksz_switch_chips[KSZ8567] + }, + { .compatible = "microchip,ksz9567", .data = &ksz_switch_chips[KSZ9567] }, diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c index 245dfb7a7a31..9ff5132f3ac6 100644 --- a/drivers/net/dsa/microchip/ksz_common.c +++ b/drivers/net/dsa/microchip/ksz_common.c @@ -1476,6 +1476,39 @@ const struct ksz_chip_data ksz_switch_chips[] = { .gbit_capable = {true, true, true}, }, + [KSZ8567] = { + .chip_id = KSZ8567_CHIP_ID, + .dev_name = "KSZ8567", + .num_vlans = 4096, + .num_alus = 4096, + .num_statics = 16, + .cpu_ports = 0x7F, /* can be configured as cpu port */ + .port_cnt = 7, /* total port count */ + .port_nirqs = 3, + .num_tx_queues = 4, + .tc_cbs_supported = true, + .tc_ets_supported = true, + .ops = &ksz9477_dev_ops, + .mib_names = ksz9477_mib_names, + .mib_cnt = ARRAY_SIZE(ksz9477_mib_names), + .reg_mib_cnt = MIB_COUNTER_NUM, + .regs = ksz9477_regs, + .masks = ksz9477_masks, + .shifts = ksz9477_shifts, + .xmii_ctrl0 = ksz9477_xmii_ctrl0, + .xmii_ctrl1 = ksz9477_xmii_ctrl1, + .supports_mii = {false, false, false, false, + false, true, true}, + .supports_rmii = {false, false, false, false, + false, true, true}, + .supports_rgmii = {false, false, false, false, + false, true, true}, + .internal_phy = {true, true, true, true, + true, false, false}, + .gbit_capable = {false, false, false, false, false, + true, true}, + }, + [KSZ9567] = { .chip_id = KSZ9567_CHIP_ID, .dev_name = "KSZ9567", @@ -2649,6 +2682,7 @@ static void ksz_port_teardown(struct dsa_switch *ds, int port) switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -2705,7 +2739,8 @@ static enum dsa_tag_protocol ksz_get_tag_protocol(struct dsa_switch *ds, dev->chip_id == KSZ9563_CHIP_ID) proto = DSA_TAG_PROTO_KSZ9893; - if (dev->chip_id == KSZ9477_CHIP_ID || + if (dev->chip_id == KSZ8567_CHIP_ID || + dev->chip_id == KSZ9477_CHIP_ID || dev->chip_id == KSZ9896_CHIP_ID || dev->chip_id == KSZ9897_CHIP_ID || dev->chip_id == KSZ9567_CHIP_ID) @@ -2813,6 +2848,7 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port) case KSZ8830_CHIP_ID: return KSZ8863_HUGE_PACKET_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN; case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -2839,6 +2875,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port) switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -2852,7 +2889,7 @@ static int ksz_validate_eee(struct dsa_switch *ds, int port) } static int ksz_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { int ret; @@ -2872,7 +2909,7 @@ static int ksz_get_mac_eee(struct dsa_switch *ds, int port, } static int ksz_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct ksz_device *dev = ds->priv; int ret; @@ -3183,6 +3220,7 @@ static int ksz_switch_detect(struct ksz_device *dev) case KSZ9896_CHIP_ID: case KSZ9897_CHIP_ID: case KSZ9567_CHIP_ID: + case KSZ8567_CHIP_ID: case LAN9370_CHIP_ID: case LAN9371_CHIP_ID: case LAN9372_CHIP_ID: @@ -3220,6 +3258,7 @@ static int ksz_cls_flower_add(struct dsa_switch *ds, int port, switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -3239,6 +3278,7 @@ static int ksz_cls_flower_del(struct dsa_switch *ds, int port, switch (dev->chip_id) { case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: @@ -4142,6 +4182,7 @@ static int ksz_parse_drive_strength(struct ksz_device *dev) case KSZ8794_CHIP_ID: case KSZ8765_CHIP_ID: case KSZ8563_CHIP_ID: + case KSZ8567_CHIP_ID: case KSZ9477_CHIP_ID: case KSZ9563_CHIP_ID: case KSZ9567_CHIP_ID: diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h index 15612101a155..060c5de9aa05 100644 --- a/drivers/net/dsa/microchip/ksz_common.h +++ b/drivers/net/dsa/microchip/ksz_common.h @@ -187,6 +187,7 @@ struct ksz_device { /* List of supported models */ enum ksz_model { KSZ8563, + KSZ8567, KSZ8795, KSZ8794, KSZ8765, diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c index 6f6d878e742c..c8166fb440ab 100644 --- a/drivers/net/dsa/microchip/ksz_spi.c +++ b/drivers/net/dsa/microchip/ksz_spi.c @@ -165,6 +165,10 @@ static const struct of_device_id ksz_dt_ids[] = { .data = &ksz_switch_chips[KSZ8563] }, { + .compatible = "microchip,ksz8567", + .data = &ksz_switch_chips[KSZ8567] + }, + { .compatible = "microchip,ksz9567", .data = &ksz_switch_chips[KSZ9567] }, @@ -204,6 +208,7 @@ static const struct spi_device_id ksz_spi_ids[] = { { "ksz9893" }, { "ksz9563" }, { "ksz8563" }, + { "ksz8567" }, { "ksz9567" }, { "lan9370" }, { "lan9371" }, diff --git a/drivers/net/dsa/mt7530-mdio.c b/drivers/net/dsa/mt7530-mdio.c index 088533663b83..fa3ee85a99c1 100644 --- a/drivers/net/dsa/mt7530-mdio.c +++ b/drivers/net/dsa/mt7530-mdio.c @@ -81,17 +81,14 @@ static const struct regmap_bus mt7530_regmap_bus = { }; static int -mt7531_create_sgmii(struct mt7530_priv *priv, bool dual_sgmii) +mt7531_create_sgmii(struct mt7530_priv *priv) { struct regmap_config *mt7531_pcs_config[2] = {}; struct phylink_pcs *pcs; struct regmap *regmap; int i, ret = 0; - /* MT7531AE has two SGMII units for port 5 and port 6 - * MT7531BE has only one SGMII unit for port 6 - */ - for (i = dual_sgmii ? 0 : 1; i < 2; i++) { + for (i = priv->p5_sgmii ? 0 : 1; i < 2; i++) { mt7531_pcs_config[i] = devm_kzalloc(priv->dev, sizeof(struct regmap_config), GFP_KERNEL); diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c index 3c1f657593a8..216596b86de8 100644 --- a/drivers/net/dsa/mt7530.c +++ b/drivers/net/dsa/mt7530.c @@ -487,15 +487,6 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface) return 0; } -static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv) -{ - u32 val; - - val = mt7530_read(priv, MT7531_TOP_SIG_SR); - - return (val & PAD_DUAL_SGMII_EN) != 0; -} - static int mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { @@ -510,9 +501,6 @@ mt7531_pll_setup(struct mt7530_priv *priv) u32 xtal; u32 val; - if (mt7531_dual_sgmii_supported(priv)) - return; - val = mt7530_read(priv, MT7531_CREV); top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR); hwstrap = mt7530_read(priv, MT7531_HWTRAP); @@ -920,8 +908,6 @@ static const char *p5_intf_modes(unsigned int p5_interface) return "PHY P4"; case P5_INTF_SEL_GMAC5: return "GMAC5"; - case P5_INTF_SEL_GMAC5_SGMII: - return "GMAC5_SGMII"; default: return "unknown"; } @@ -956,9 +942,6 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) /* MT7530_P5_MODE_GMAC: P5 -> External phy or 2nd GMAC */ val &= ~MHWTRAP_P5_DIS; break; - case P5_DISABLED: - interface = PHY_INTERFACE_MODE_NA; - break; default: dev_err(ds->dev, "Unsupported p5_intf_sel %d\n", priv->p5_intf_sel); @@ -992,8 +975,6 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface) dev_dbg(ds->dev, "Setup P5, HWTRAP=0x%x, intf_sel=%s, phy-mode=%s\n", val, p5_intf_modes(priv->p5_intf_sel), phy_modes(interface)); - priv->p5_interface = interface; - unlock_exit: mutex_unlock(&priv->reg_mutex); } @@ -1035,10 +1016,6 @@ mt753x_cpu_port_enable(struct dsa_switch *ds, int port) mt7530_set(priv, MT7530_MFC, BC_FFP(BIT(port)) | UNM_FFP(BIT(port)) | UNU_FFP(BIT(port))); - /* Set CPU port number */ - if (priv->id == ID_MT7530 || priv->id == ID_MT7621) - mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port)); - /* Add the CPU port to the CPU port bitmap for MT7531 and the switch on * the MT7988 SoC. Trapped frames will be forwarded to the CPU port that * is affine to the inbound user port. @@ -2146,24 +2123,40 @@ mt7530_free_irq_common(struct mt7530_priv *priv) static void mt7530_free_irq(struct mt7530_priv *priv) { - mt7530_free_mdio_irq(priv); + struct device_node *mnp, *np = priv->dev->of_node; + + mnp = of_get_child_by_name(np, "mdio"); + if (!mnp) + mt7530_free_mdio_irq(priv); + of_node_put(mnp); + mt7530_free_irq_common(priv); } static int mt7530_setup_mdio(struct mt7530_priv *priv) { + struct device_node *mnp, *np = priv->dev->of_node; struct dsa_switch *ds = priv->ds; struct device *dev = priv->dev; struct mii_bus *bus; static int idx; - int ret; + int ret = 0; + + mnp = of_get_child_by_name(np, "mdio"); + + if (mnp && !of_device_is_available(mnp)) + goto out; bus = devm_mdiobus_alloc(dev); - if (!bus) - return -ENOMEM; + if (!bus) { + ret = -ENOMEM; + goto out; + } + + if (!mnp) + ds->user_mii_bus = bus; - ds->user_mii_bus = bus; bus->priv = priv; bus->name = KBUILD_MODNAME "-mii"; snprintf(bus->id, MII_BUS_ID_SIZE, KBUILD_MODNAME "-%d", idx++); @@ -2174,16 +2167,18 @@ mt7530_setup_mdio(struct mt7530_priv *priv) bus->parent = dev; bus->phy_mask = ~ds->phys_mii_mask; - if (priv->irq) + if (priv->irq && !mnp) mt7530_setup_mdio_irq(priv); - ret = devm_mdiobus_register(dev, bus); + ret = devm_of_mdiobus_register(dev, bus, mnp); if (ret) { dev_err(dev, "failed to register MDIO bus: %d\n", ret); - if (priv->irq) + if (priv->irq && !mnp) mt7530_free_mdio_irq(priv); } +out: + of_node_put(mnp); return ret; } @@ -2326,16 +2321,13 @@ mt7530_setup(struct dsa_switch *ds) return ret; /* Setup port 5 */ - priv->p5_intf_sel = P5_DISABLED; - interface = PHY_INTERFACE_MODE_NA; - if (!dsa_is_unused_port(ds, 5)) { priv->p5_intf_sel = P5_INTF_SEL_GMAC5; - ret = of_get_phy_mode(dsa_to_port(ds, 5)->dn, &interface); - if (ret && ret != -ENODEV) - return ret; } else { - /* Scan the ethernet nodes. look for GMAC1, lookup used phy */ + /* Scan the ethernet nodes. Look for GMAC1, lookup the used PHY. + * Set priv->p5_intf_sel to the appropriate value if PHY muxing + * is detected. + */ for_each_child_of_node(dn, mac_np) { if (!of_device_is_compatible(mac_np, "mediatek,eth-mac")) @@ -2366,6 +2358,10 @@ mt7530_setup(struct dsa_switch *ds) of_node_put(phy_node); break; } + + if (priv->p5_intf_sel == P5_INTF_SEL_PHY_P0 || + priv->p5_intf_sel == P5_INTF_SEL_PHY_P4) + mt7530_setup_port5(ds, interface); } #ifdef CONFIG_GPIOLIB @@ -2376,8 +2372,6 @@ mt7530_setup(struct dsa_switch *ds) } #endif /* CONFIG_GPIOLIB */ - mt7530_setup_port5(ds, interface); - /* Flush the FDB table */ ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL); if (ret < 0) @@ -2474,6 +2468,12 @@ mt7531_setup(struct dsa_switch *ds) return -ENODEV; } + /* MT7531AE has got two SGMII units. One for port 5, one for port 6. + * MT7531BE has got only one SGMII unit which is for port 6. + */ + val = mt7530_read(priv, MT7531_TOP_SIG_SR); + priv->p5_sgmii = !!(val & PAD_DUAL_SGMII_EN); + /* 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); @@ -2483,21 +2483,18 @@ mt7531_setup(struct dsa_switch *ds) 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; - + if (!priv->p5_sgmii) { + mt7531_pll_setup(priv); + } else { /* Let ds->user_mii_bus be able to access external phy. */ mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK, MT7531_EXT_P_MDC_11); mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK, MT7531_EXT_P_MDIO_12); - } else { - priv->p5_intf_sel = P5_INTF_SEL_GMAC5; } - dev_dbg(ds->dev, "P5 support %s interface\n", - p5_intf_modes(priv->p5_intf_sel)); + + if (!dsa_is_unused_port(ds, 5)) + priv->p5_intf_sel = P5_INTF_SEL_GMAC5; mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK, MT7531_GPIO0_INTERRUPT); @@ -2535,12 +2532,14 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces); break; - case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ + /* Port 5 supports rgmii with delays, mii, and gmii. */ + case 5: phy_interface_set_rgmii(config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces); @@ -2548,7 +2547,8 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, config->supported_interfaces); break; - case 6: /* 1st cpu port */ + /* Port 6 supports rgmii and trgmii. */ + case 6: __set_bit(PHY_INTERFACE_MODE_RGMII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_TRGMII, @@ -2557,30 +2557,30 @@ static void mt7530_mac_port_get_caps(struct dsa_switch *ds, int port, } } -static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port) -{ - return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII); -} - static void mt7531_mac_port_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config) { struct mt7530_priv *priv = ds->priv; switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_GMII, config->supported_interfaces); break; - case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */ - if (mt7531_is_rgmii_port(priv, port)) { + /* Port 5 supports rgmii with delays on MT7531BE, sgmii/802.3z on + * MT7531AE. + */ + case 5: + if (!priv->p5_sgmii) { phy_interface_set_rgmii(config->supported_interfaces); break; } fallthrough; - case 6: /* 1st cpu port supports sgmii/8023z only */ + /* Port 6 supports sgmii/802.3z. */ + case 6: __set_bit(PHY_INTERFACE_MODE_SGMII, config->supported_interfaces); __set_bit(PHY_INTERFACE_MODE_1000BASEX, @@ -2599,11 +2599,13 @@ static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port, phy_interface_zero(config->supported_interfaces); switch (port) { - case 0 ... 4: /* Internal phy */ + /* Ports which are connected to switch PHYs. There is no MII pinout. */ + case 0 ... 4: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); break; + /* Port 6 is connected to SoC's XGMII MAC. There is no MII pinout. */ case 6: __set_bit(PHY_INTERFACE_MODE_INTERNAL, config->supported_interfaces); @@ -2641,7 +2643,7 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port, { u32 val; - if (!mt7531_is_rgmii_port(priv, port)) { + if (priv->p5_sgmii) { dev_err(priv->dev, "RGMII mode is not available for port %d\n", port); return -EINVAL; @@ -2767,12 +2769,12 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, u32 mcr_cur, mcr_new; switch (port) { - case 0 ... 4: /* Internal phy */ + case 0 ... 4: if (state->interface != PHY_INTERFACE_MODE_GMII && state->interface != PHY_INTERFACE_MODE_INTERNAL) goto unsupported; break; - case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */ + case 5: if (priv->p5_interface == state->interface) break; @@ -2782,7 +2784,7 @@ mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode, if (priv->p5_intf_sel != P5_DISABLED) priv->p5_interface = state->interface; break; - case 6: /* 1st cpu port */ + case 6: if (priv->p6_interface == state->interface) break; @@ -2884,7 +2886,7 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port) switch (port) { case 5: - if (mt7531_is_rgmii_port(priv, port)) + if (!priv->p5_sgmii) interface = PHY_INTERFACE_MODE_RGMII; else interface = PHY_INTERFACE_MODE_2500BASEX; @@ -3036,7 +3038,7 @@ mt753x_setup(struct dsa_switch *ds) mt7530_free_irq_common(priv); if (priv->create_sgmii) { - ret = priv->create_sgmii(priv, mt7531_dual_sgmii_supported(priv)); + ret = priv->create_sgmii(priv); if (ret && priv->irq) mt7530_free_irq(priv); } @@ -3045,7 +3047,7 @@ mt753x_setup(struct dsa_switch *ds) } static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct mt7530_priv *priv = ds->priv; u32 eeecr = mt7530_read(priv, MT7530_PMEEECR_P(port)); @@ -3057,7 +3059,7 @@ static int mt753x_get_mac_eee(struct dsa_switch *ds, int port, } static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { struct mt7530_priv *priv = ds->priv; u32 set, mask = LPI_THRESH_MASK | LPI_MODE_EN; @@ -3074,6 +3076,36 @@ static int mt753x_set_mac_eee(struct dsa_switch *ds, int port, return 0; } +static void +mt753x_conduit_state_change(struct dsa_switch *ds, + const struct net_device *conduit, + bool operational) +{ + struct dsa_port *cpu_dp = conduit->dsa_ptr; + struct mt7530_priv *priv = ds->priv; + int val = 0; + u8 mask; + + /* Set the CPU port to trap frames to for MT7530. Trapped frames will be + * forwarded to the numerically smallest CPU port whose conduit + * interface is up. + */ + if (priv->id != ID_MT7530 && priv->id != ID_MT7621) + return; + + mask = BIT(cpu_dp->index); + + if (operational) + priv->active_cpu_ports |= mask; + else + priv->active_cpu_ports &= ~mask; + + if (priv->active_cpu_ports) + val = CPU_EN | CPU_PORT(__ffs(priv->active_cpu_ports)); + + mt7530_rmw(priv, MT7530_MFC, CPU_EN | CPU_PORT_MASK, val); +} + static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface) { return 0; @@ -3129,6 +3161,7 @@ const struct dsa_switch_ops mt7530_switch_ops = { .phylink_mac_link_up = mt753x_phylink_mac_link_up, .get_mac_eee = mt753x_get_mac_eee, .set_mac_eee = mt753x_set_mac_eee, + .conduit_state_change = mt753x_conduit_state_change, }; EXPORT_SYMBOL_GPL(mt7530_switch_ops); diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h index 17e42d30fff4..80060cc740d2 100644 --- a/drivers/net/dsa/mt7530.h +++ b/drivers/net/dsa/mt7530.h @@ -41,8 +41,8 @@ enum mt753x_id { #define UNU_FFP(x) (((x) & 0xff) << 8) #define UNU_FFP_MASK UNU_FFP(~0) #define CPU_EN BIT(7) -#define CPU_PORT(x) ((x) << 4) -#define CPU_MASK (0xf << 4) +#define CPU_PORT_MASK GENMASK(6, 4) +#define CPU_PORT(x) FIELD_PREP(CPU_PORT_MASK, x) #define MIRROR_EN BIT(3) #define MIRROR_PORT(x) ((x) & 0x7) #define MIRROR_MASK 0x7 @@ -683,11 +683,10 @@ struct mt7530_port { /* Port 5 interface select definitions */ enum p5_interface_select { - P5_DISABLED = 0, + P5_DISABLED, P5_INTF_SEL_PHY_P0, P5_INTF_SEL_PHY_P4, P5_INTF_SEL_GMAC5, - P5_INTF_SEL_GMAC5_SGMII, }; struct mt7530_priv; @@ -756,10 +755,13 @@ struct mt753x_info { * registers * @p6_interface Holding the current port 6 interface * @p5_intf_sel: Holding the current port 5 interface select + * @p5_sgmii: Flag for distinguishing if port 5 of the MT7531 switch + * has got SGMII * @irq: IRQ number of the switch * @irq_domain: IRQ domain of the switch irq_chip * @irq_enable: IRQ enable bits, synced to SYS_INT_EN * @create_sgmii: Pointer to function creating SGMII PCS instance(s) + * @active_cpu_ports: Holding the active CPU ports */ struct mt7530_priv { struct device *dev; @@ -775,7 +777,8 @@ struct mt7530_priv { bool mcm; phy_interface_t p6_interface; phy_interface_t p5_interface; - unsigned int p5_intf_sel; + enum p5_interface_select p5_intf_sel; + bool p5_sgmii; u8 mirror_rx; u8 mirror_tx; struct mt7530_port ports[MT7530_NUM_PORTS]; @@ -785,7 +788,8 @@ struct mt7530_priv { int irq; struct irq_domain *irq_domain; u32 irq_enable; - int (*create_sgmii)(struct mt7530_priv *priv, bool dual_sgmii); + int (*create_sgmii)(struct mt7530_priv *priv); + u8 active_cpu_ports; }; struct mt7530_hw_vlan_entry { diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 614cabb5c1b0..6eec2e4aa031 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1451,14 +1451,14 @@ static void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, } static int mv88e6xxx_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; } static int mv88e6xxx_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c index 2358cd399c7e..7f80035c5441 100644 --- a/drivers/net/dsa/qca/qca8k-common.c +++ b/drivers/net/dsa/qca/qca8k-common.c @@ -534,7 +534,7 @@ int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset) } int qca8k_set_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { u32 lpi_en = QCA8K_REG_EEE_CTRL_LPI_EN(port); struct qca8k_priv *priv = ds->priv; @@ -558,7 +558,7 @@ exit: } int qca8k_get_mac_eee(struct dsa_switch *ds, int port, - struct ethtool_eee *e) + struct ethtool_keee *e) { /* Nothing to do on the port's MAC */ return 0; diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h index c8785c36c54e..2184d8d2d5a9 100644 --- a/drivers/net/dsa/qca/qca8k.h +++ b/drivers/net/dsa/qca/qca8k.h @@ -518,8 +518,8 @@ void qca8k_get_ethtool_stats(struct dsa_switch *ds, int port, int qca8k_get_sset_count(struct dsa_switch *ds, int port, int sset); /* Common eee function */ -int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *eee); -int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); +int qca8k_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *eee); +int qca8k_get_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e); /* Common bridge function */ void qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state); diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 633b321d7fdd..9e9e4a03f1a8 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -90,8 +90,7 @@ static int ena_com_admin_init_sq(struct ena_com_admin_queue *admin_queue) struct ena_com_admin_sq *sq = &admin_queue->sq; u16 size = ADMIN_SQ_SIZE(admin_queue->q_depth); - sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, - &sq->dma_addr, GFP_KERNEL); + sq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &sq->dma_addr, GFP_KERNEL); if (!sq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -113,8 +112,7 @@ static int ena_com_admin_init_cq(struct ena_com_admin_queue *admin_queue) struct ena_com_admin_cq *cq = &admin_queue->cq; u16 size = ADMIN_CQ_SIZE(admin_queue->q_depth); - cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, - &cq->dma_addr, GFP_KERNEL); + cq->entries = dma_alloc_coherent(admin_queue->q_dmadev, size, &cq->dma_addr, GFP_KERNEL); if (!cq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -136,8 +134,7 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, ena_dev->aenq.q_depth = ENA_ASYNC_QUEUE_DEPTH; size = ADMIN_AENQ_SIZE(ENA_ASYNC_QUEUE_DEPTH); - aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, - &aenq->dma_addr, GFP_KERNEL); + aenq->entries = dma_alloc_coherent(ena_dev->dmadev, size, &aenq->dma_addr, GFP_KERNEL); if (!aenq->entries) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); @@ -155,14 +152,13 @@ static int ena_com_admin_init_aenq(struct ena_com_dev *ena_dev, aenq_caps = 0; aenq_caps |= ena_dev->aenq.q_depth & ENA_REGS_AENQ_CAPS_AENQ_DEPTH_MASK; - aenq_caps |= (sizeof(struct ena_admin_aenq_entry) - << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & - ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; + aenq_caps |= + (sizeof(struct ena_admin_aenq_entry) << ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_SHIFT) & + ENA_REGS_AENQ_CAPS_AENQ_ENTRY_SIZE_MASK; writel(aenq_caps, ena_dev->reg_bar + ENA_REGS_AENQ_CAPS_OFF); if (unlikely(!aenq_handlers)) { - netdev_err(ena_dev->net_device, - "AENQ handlers pointer is NULL\n"); + netdev_err(ena_dev->net_device, "AENQ handlers pointer is NULL\n"); return -EINVAL; } @@ -189,14 +185,12 @@ static struct ena_comp_ctx *get_comp_ctxt(struct ena_com_admin_queue *admin_queu } if (unlikely(!admin_queue->comp_ctx)) { - netdev_err(admin_queue->ena_dev->net_device, - "Completion context is NULL\n"); + netdev_err(admin_queue->ena_dev->net_device, "Completion context is NULL\n"); return NULL; } if (unlikely(admin_queue->comp_ctx[command_id].occupied && capture)) { - netdev_err(admin_queue->ena_dev->net_device, - "Completion context is occupied\n"); + netdev_err(admin_queue->ena_dev->net_device, "Completion context is occupied\n"); return NULL; } @@ -226,8 +220,7 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu /* In case of queue FULL */ cnt = (u16)atomic_read(&admin_queue->outstanding_cmds); if (cnt >= admin_queue->q_depth) { - netdev_dbg(admin_queue->ena_dev->net_device, - "Admin queue is full.\n"); + netdev_dbg(admin_queue->ena_dev->net_device, "Admin queue is full.\n"); admin_queue->stats.out_of_space++; return ERR_PTR(-ENOSPC); } @@ -274,8 +267,7 @@ static int ena_com_init_comp_ctxt(struct ena_com_admin_queue *admin_queue) struct ena_comp_ctx *comp_ctx; u16 i; - admin_queue->comp_ctx = - devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); + admin_queue->comp_ctx = devm_kzalloc(admin_queue->q_dmadev, size, GFP_KERNEL); if (unlikely(!admin_queue->comp_ctx)) { netdev_err(ena_dev->net_device, "Memory allocation failed\n"); return -ENOMEM; @@ -336,20 +328,17 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_sq->desc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, + dma_alloc_coherent(ena_dev->dmadev, size, &io_sq->desc_addr.phys_addr, GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); if (!io_sq->desc_addr.virt_addr) { io_sq->desc_addr.virt_addr = dma_alloc_coherent(ena_dev->dmadev, size, - &io_sq->desc_addr.phys_addr, - GFP_KERNEL); + &io_sq->desc_addr.phys_addr, GFP_KERNEL); } if (!io_sq->desc_addr.virt_addr) { - netdev_err(ena_dev->net_device, - "Memory allocation failed\n"); + netdev_err(ena_dev->net_device, "Memory allocation failed\n"); return -ENOMEM; } } @@ -367,16 +356,14 @@ static int ena_com_init_io_sq(struct ena_com_dev *ena_dev, dev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); - io_sq->bounce_buf_ctrl.base_buffer = - devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); + io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); set_dev_node(ena_dev->dmadev, dev_node); if (!io_sq->bounce_buf_ctrl.base_buffer) io_sq->bounce_buf_ctrl.base_buffer = devm_kzalloc(ena_dev->dmadev, size, GFP_KERNEL); if (!io_sq->bounce_buf_ctrl.base_buffer) { - netdev_err(ena_dev->net_device, - "Bounce buffer memory allocation failed\n"); + netdev_err(ena_dev->net_device, "Bounce buffer memory allocation failed\n"); return -ENOMEM; } @@ -425,13 +412,11 @@ static int ena_com_init_io_cq(struct ena_com_dev *ena_dev, prev_node = dev_to_node(ena_dev->dmadev); set_dev_node(ena_dev->dmadev, ctx->numa_node); io_cq->cdesc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); + dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); set_dev_node(ena_dev->dmadev, prev_node); if (!io_cq->cdesc_addr.virt_addr) { io_cq->cdesc_addr.virt_addr = - dma_alloc_coherent(ena_dev->dmadev, size, - &io_cq->cdesc_addr.phys_addr, + dma_alloc_coherent(ena_dev->dmadev, size, &io_cq->cdesc_addr.phys_addr, GFP_KERNEL); } @@ -514,8 +499,8 @@ static int ena_com_comp_status_to_errno(struct ena_com_admin_queue *admin_queue, u8 comp_status) { if (unlikely(comp_status != 0)) - netdev_err(admin_queue->ena_dev->net_device, - "Admin command failed[%u]\n", comp_status); + netdev_err(admin_queue->ena_dev->net_device, "Admin command failed[%u]\n", + comp_status); switch (comp_status) { case ENA_ADMIN_SUCCESS: @@ -580,8 +565,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c } if (unlikely(comp_ctx->status == ENA_CMD_ABORTED)) { - netdev_err(admin_queue->ena_dev->net_device, - "Command was aborted\n"); + netdev_err(admin_queue->ena_dev->net_device, "Command was aborted\n"); spin_lock_irqsave(&admin_queue->q_lock, flags); admin_queue->stats.aborted_cmd++; spin_unlock_irqrestore(&admin_queue->q_lock, flags); @@ -589,8 +573,7 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c goto err; } - WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", - comp_ctx->status); + WARN(comp_ctx->status != ENA_CMD_COMPLETED, "Invalid comp status %d\n", comp_ctx->status); ret = ena_com_comp_status_to_errno(admin_queue, comp_ctx->comp_status); err: @@ -634,8 +617,7 @@ static int ena_com_set_llq(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set LLQ configurations: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set LLQ configurations: %d\n", ret); return ret; } @@ -658,8 +640,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, llq_default_cfg->llq_header_location; } else { netdev_err(ena_dev->net_device, - "Invalid header location control, supported: 0x%x\n", - supported_feat); + "Invalid header location control, supported: 0x%x\n", supported_feat); return -EINVAL; } @@ -681,8 +662,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, netdev_err(ena_dev->net_device, "Default llq stride ctrl is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", - llq_default_cfg->llq_stride_ctrl, - supported_feat, llq_info->desc_stride_ctrl); + llq_default_cfg->llq_stride_ctrl, supported_feat, + llq_info->desc_stride_ctrl); } } else { llq_info->desc_stride_ctrl = 0; @@ -704,8 +685,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, llq_info->desc_list_entry_size = 256; } else { netdev_err(ena_dev->net_device, - "Invalid entry_size_ctrl, supported: 0x%x\n", - supported_feat); + "Invalid entry_size_ctrl, supported: 0x%x\n", supported_feat); return -EINVAL; } @@ -750,8 +730,8 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, netdev_err(ena_dev->net_device, "Default llq num descs before header is not supported, performing fallback, default: 0x%x, supported: 0x%x, used: 0x%x\n", - llq_default_cfg->llq_num_decs_before_header, - supported_feat, llq_info->descs_num_before_header); + llq_default_cfg->llq_num_decs_before_header, supported_feat, + llq_info->descs_num_before_header); } /* Check for accelerated queue supported */ llq_accel_mode_get = llq_features->accel_mode.u.get; @@ -767,8 +747,7 @@ static int ena_com_config_llq_info(struct ena_com_dev *ena_dev, rc = ena_com_set_llq(ena_dev); if (rc) - netdev_err(ena_dev->net_device, - "Cannot set LLQ configuration: %d\n", rc); + netdev_err(ena_dev->net_device, "Cannot set LLQ configuration: %d\n", rc); return rc; } @@ -780,8 +759,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com int ret; wait_for_completion_timeout(&comp_ctx->wait_event, - usecs_to_jiffies( - admin_queue->completion_timeout)); + usecs_to_jiffies(admin_queue->completion_timeout)); /* In case the command wasn't completed find out the root cause. * There might be 2 kinds of errors @@ -797,8 +775,7 @@ static int ena_com_wait_and_process_admin_cq_interrupts(struct ena_comp_ctx *com if (comp_ctx->status == ENA_CMD_COMPLETED) { netdev_err(admin_queue->ena_dev->net_device, "The ena device sent a completion but the driver didn't receive a MSI-X interrupt (cmd %d), autopolling mode is %s\n", - comp_ctx->cmd_opcode, - admin_queue->auto_polling ? "ON" : "OFF"); + comp_ctx->cmd_opcode, admin_queue->auto_polling ? "ON" : "OFF"); /* Check if fallback to polling is enabled */ if (admin_queue->auto_polling) admin_queue->polling = true; @@ -867,15 +844,13 @@ static u32 ena_com_reg_bar_read32(struct ena_com_dev *ena_dev, u16 offset) if (unlikely(i == timeout)) { netdev_err(ena_dev->net_device, "Reading reg failed for timeout. expected: req id[%u] offset[%u] actual: req id[%u] offset[%u]\n", - mmio_read->seq_num, offset, read_resp->req_id, - read_resp->reg_off); + mmio_read->seq_num, offset, read_resp->req_id, read_resp->reg_off); ret = ENA_MMIO_READ_TIMEOUT; goto err; } if (read_resp->reg_off != offset) { - netdev_err(ena_dev->net_device, - "Read failure: wrong offset provided\n"); + netdev_err(ena_dev->net_device, "Read failure: wrong offset provided\n"); ret = ENA_MMIO_READ_TIMEOUT; } else { ret = read_resp->reg_val; @@ -934,8 +909,7 @@ static int ena_com_destroy_io_sq(struct ena_com_dev *ena_dev, sizeof(destroy_resp)); if (unlikely(ret && (ret != -ENODEV))) - netdev_err(ena_dev->net_device, - "Failed to destroy io sq error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to destroy io sq error: %d\n", ret); return ret; } @@ -949,8 +923,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, if (io_cq->cdesc_addr.virt_addr) { size = io_cq->cdesc_entry_size_in_bytes * io_cq->q_depth; - dma_free_coherent(ena_dev->dmadev, size, - io_cq->cdesc_addr.virt_addr, + dma_free_coherent(ena_dev->dmadev, size, io_cq->cdesc_addr.virt_addr, io_cq->cdesc_addr.phys_addr); io_cq->cdesc_addr.virt_addr = NULL; @@ -959,8 +932,7 @@ static void ena_com_io_queue_free(struct ena_com_dev *ena_dev, if (io_sq->desc_addr.virt_addr) { size = io_sq->desc_entry_size * io_sq->q_depth; - dma_free_coherent(ena_dev->dmadev, size, - io_sq->desc_addr.virt_addr, + dma_free_coherent(ena_dev->dmadev, size, io_sq->desc_addr.virt_addr, io_sq->desc_addr.phys_addr); io_sq->desc_addr.virt_addr = NULL; @@ -985,8 +957,7 @@ static int wait_for_reset_state(struct ena_com_dev *ena_dev, u32 timeout, val = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); if (unlikely(val == ENA_MMIO_READ_TIMEOUT)) { - netdev_err(ena_dev->net_device, - "Reg read timeout occurred\n"); + netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); return -ETIME; } @@ -1026,8 +997,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, int ret; if (!ena_com_check_supported_feature_id(ena_dev, feature_id)) { - netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", - feature_id); + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", feature_id); return -EOPNOTSUPP; } @@ -1064,8 +1034,7 @@ static int ena_com_get_feature_ex(struct ena_com_dev *ena_dev, if (unlikely(ret)) netdev_err(ena_dev->net_device, - "Failed to submit get_feature command %d error: %d\n", - feature_id, ret); + "Failed to submit get_feature command %d error: %d\n", feature_id, ret); return ret; } @@ -1104,13 +1073,11 @@ static int ena_com_hash_key_allocate(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_FUNCTION)) + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) return -EOPNOTSUPP; - rss->hash_key = - dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), - &rss->hash_key_dma_addr, GFP_KERNEL); + rss->hash_key = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), + &rss->hash_key_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_key)) return -ENOMEM; @@ -1123,8 +1090,8 @@ static void ena_com_hash_key_destroy(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; if (rss->hash_key) - dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), - rss->hash_key, rss->hash_key_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_key), rss->hash_key, + rss->hash_key_dma_addr); rss->hash_key = NULL; } @@ -1132,9 +1099,8 @@ static int ena_com_hash_ctrl_init(struct ena_com_dev *ena_dev) { struct ena_rss *rss = &ena_dev->rss; - rss->hash_ctrl = - dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), - &rss->hash_ctrl_dma_addr, GFP_KERNEL); + rss->hash_ctrl = dma_alloc_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), + &rss->hash_ctrl_dma_addr, GFP_KERNEL); if (unlikely(!rss->hash_ctrl)) return -ENOMEM; @@ -1147,8 +1113,8 @@ static void ena_com_hash_ctrl_destroy(struct ena_com_dev *ena_dev) struct ena_rss *rss = &ena_dev->rss; if (rss->hash_ctrl) - dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), - rss->hash_ctrl, rss->hash_ctrl_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*rss->hash_ctrl), rss->hash_ctrl, + rss->hash_ctrl_dma_addr); rss->hash_ctrl = NULL; } @@ -1177,15 +1143,13 @@ static int ena_com_indirect_table_allocate(struct ena_com_dev *ena_dev, tbl_size = (1ULL << log_size) * sizeof(struct ena_admin_rss_ind_table_entry); - rss->rss_ind_tbl = - dma_alloc_coherent(ena_dev->dmadev, tbl_size, - &rss->rss_ind_tbl_dma_addr, GFP_KERNEL); + rss->rss_ind_tbl = dma_alloc_coherent(ena_dev->dmadev, tbl_size, &rss->rss_ind_tbl_dma_addr, + GFP_KERNEL); if (unlikely(!rss->rss_ind_tbl)) goto mem_err1; tbl_size = (1ULL << log_size) * sizeof(u16); - rss->host_rss_ind_tbl = - devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); + rss->host_rss_ind_tbl = devm_kzalloc(ena_dev->dmadev, tbl_size, GFP_KERNEL); if (unlikely(!rss->host_rss_ind_tbl)) goto mem_err2; @@ -1197,8 +1161,7 @@ mem_err2: tbl_size = (1ULL << log_size) * sizeof(struct ena_admin_rss_ind_table_entry); - dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, - rss->rss_ind_tbl_dma_addr); + dma_free_coherent(ena_dev->dmadev, tbl_size, rss->rss_ind_tbl, rss->rss_ind_tbl_dma_addr); rss->rss_ind_tbl = NULL; mem_err1: rss->tbl_log_size = 0; @@ -1261,8 +1224,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, &create_cmd.sq_ba, io_sq->desc_addr.phys_addr); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Memory address set failed\n"); + netdev_err(ena_dev->net_device, "Memory address set failed\n"); return ret; } } @@ -1273,8 +1235,7 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, (struct ena_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to create IO SQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to create IO SQ. error: %d\n", ret); return ret; } @@ -1284,16 +1245,12 @@ static int ena_com_create_io_sq(struct ena_com_dev *ena_dev, (uintptr_t)cmd_completion.sq_doorbell_offset); if (io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - io_sq->header_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar - + cmd_completion.llq_headers_offset); - io_sq->desc_addr.pbuf_dev_addr = (u8 __iomem *)((uintptr_t)ena_dev->mem_bar + cmd_completion.llq_descriptors_offset); } - netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", - io_sq->idx, io_sq->q_depth); + netdev_dbg(ena_dev->net_device, "Created sq[%u], depth[%u]\n", io_sq->idx, io_sq->q_depth); return ret; } @@ -1420,8 +1377,7 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, (struct ena_admin_acq_entry *)&cmd_completion, sizeof(cmd_completion)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to create IO CQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to create IO CQ. error: %d\n", ret); return ret; } @@ -1430,18 +1386,12 @@ int ena_com_create_io_cq(struct ena_com_dev *ena_dev, io_cq->unmask_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + cmd_completion.cq_interrupt_unmask_register_offset); - if (cmd_completion.cq_head_db_register_offset) - io_cq->cq_head_db_reg = - (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + - cmd_completion.cq_head_db_register_offset); - if (cmd_completion.numa_node_register_offset) io_cq->numa_node_cfg_reg = (u32 __iomem *)((uintptr_t)ena_dev->reg_bar + cmd_completion.numa_node_register_offset); - netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", - io_cq->idx, io_cq->q_depth); + netdev_dbg(ena_dev->net_device, "Created cq[%u], depth[%u]\n", io_cq->idx, io_cq->q_depth); return ret; } @@ -1451,8 +1401,7 @@ int ena_com_get_io_handlers(struct ena_com_dev *ena_dev, u16 qid, struct ena_com_io_cq **io_cq) { if (qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Invalid queue number %d but the max is %d\n", qid, + netdev_err(ena_dev->net_device, "Invalid queue number %d but the max is %d\n", qid, ENA_TOTAL_NUM_QUEUES); return -EINVAL; } @@ -1492,8 +1441,7 @@ void ena_com_wait_for_abort_completion(struct ena_com_dev *ena_dev) spin_lock_irqsave(&admin_queue->q_lock, flags); while (atomic_read(&admin_queue->outstanding_cmds) != 0) { spin_unlock_irqrestore(&admin_queue->q_lock, flags); - ena_delay_exponential_backoff_us(exp++, - ena_dev->ena_min_poll_delay_us); + ena_delay_exponential_backoff_us(exp++, ena_dev->ena_min_poll_delay_us); spin_lock_irqsave(&admin_queue->q_lock, flags); } spin_unlock_irqrestore(&admin_queue->q_lock, flags); @@ -1519,8 +1467,7 @@ int ena_com_destroy_io_cq(struct ena_com_dev *ena_dev, sizeof(destroy_resp)); if (unlikely(ret && (ret != -ENODEV))) - netdev_err(ena_dev->net_device, - "Failed to destroy IO CQ. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to destroy IO CQ. error: %d\n", ret); return ret; } @@ -1588,8 +1535,7 @@ int ena_com_set_aenq_config(struct ena_com_dev *ena_dev, u32 groups_flag) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to config AENQ ret: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to config AENQ ret: %d\n", ret); return ret; } @@ -1610,8 +1556,7 @@ int ena_com_get_dma_width(struct ena_com_dev *ena_dev) netdev_dbg(ena_dev->net_device, "ENA dma width: %d\n", width); if ((width < 32) || width > ENA_MAX_PHYS_ADDR_SIZE_BITS) { - netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", - width); + netdev_err(ena_dev->net_device, "DMA width illegal value: %d\n", width); return -EINVAL; } @@ -1633,19 +1578,16 @@ int ena_com_validate_version(struct ena_com_dev *ena_dev) ctrl_ver = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CONTROLLER_VERSION_OFF); - if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || - (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { + if (unlikely((ver == ENA_MMIO_READ_TIMEOUT) || (ctrl_ver == ENA_MMIO_READ_TIMEOUT))) { netdev_err(ena_dev->net_device, "Reg read timeout occurred\n"); return -ETIME; } dev_info(ena_dev->dmadev, "ENA device version: %d.%d\n", - (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> - ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, + (ver & ENA_REGS_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_VERSION_MAJOR_VERSION_SHIFT, ver & ENA_REGS_VERSION_MINOR_VERSION_MASK); - dev_info(ena_dev->dmadev, - "ENA controller version: %d.%d.%d implementation version %d\n", + dev_info(ena_dev->dmadev, "ENA controller version: %d.%d.%d implementation version %d\n", (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_MASK) >> ENA_REGS_CONTROLLER_VERSION_MAJOR_VERSION_SHIFT, (ctrl_ver & ENA_REGS_CONTROLLER_VERSION_MINOR_VERSION_MASK) >> @@ -1694,20 +1636,17 @@ void ena_com_admin_destroy(struct ena_com_dev *ena_dev) size = ADMIN_SQ_SIZE(admin_queue->q_depth); if (sq->entries) - dma_free_coherent(ena_dev->dmadev, size, sq->entries, - sq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, sq->entries, sq->dma_addr); sq->entries = NULL; size = ADMIN_CQ_SIZE(admin_queue->q_depth); if (cq->entries) - dma_free_coherent(ena_dev->dmadev, size, cq->entries, - cq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, cq->entries, cq->dma_addr); cq->entries = NULL; size = ADMIN_AENQ_SIZE(aenq->q_depth); if (ena_dev->aenq.entries) - dma_free_coherent(ena_dev->dmadev, size, aenq->entries, - aenq->dma_addr); + dma_free_coherent(ena_dev->dmadev, size, aenq->entries, aenq->dma_addr); aenq->entries = NULL; } @@ -1733,10 +1672,8 @@ int ena_com_mmio_reg_read_request_init(struct ena_com_dev *ena_dev) struct ena_com_mmio_read *mmio_read = &ena_dev->mmio_read; spin_lock_init(&mmio_read->lock); - mmio_read->read_resp = - dma_alloc_coherent(ena_dev->dmadev, - sizeof(*mmio_read->read_resp), - &mmio_read->read_resp_dma_addr, GFP_KERNEL); + mmio_read->read_resp = dma_alloc_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), + &mmio_read->read_resp_dma_addr, GFP_KERNEL); if (unlikely(!mmio_read->read_resp)) goto err; @@ -1767,8 +1704,8 @@ void ena_com_mmio_reg_read_request_destroy(struct ena_com_dev *ena_dev) writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_LO_OFF); writel(0x0, ena_dev->reg_bar + ENA_REGS_MMIO_RESP_HI_OFF); - dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), - mmio_read->read_resp, mmio_read->read_resp_dma_addr); + dma_free_coherent(ena_dev->dmadev, sizeof(*mmio_read->read_resp), mmio_read->read_resp, + mmio_read->read_resp_dma_addr); mmio_read->read_resp = NULL; } @@ -1800,8 +1737,7 @@ int ena_com_admin_init(struct ena_com_dev *ena_dev, } if (!(dev_sts & ENA_REGS_DEV_STS_READY_MASK)) { - netdev_err(ena_dev->net_device, - "Device isn't ready, abort com init\n"); + netdev_err(ena_dev->net_device, "Device isn't ready, abort com init\n"); return -ENODEV; } @@ -1878,8 +1814,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, int ret; if (ctx->qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Qid (%d) is bigger than max num of queues (%d)\n", + netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", ctx->qid, ENA_TOTAL_NUM_QUEUES); return -EINVAL; } @@ -1905,8 +1840,7 @@ int ena_com_create_io_queue(struct ena_com_dev *ena_dev, if (ctx->direction == ENA_COM_IO_QUEUE_DIRECTION_TX) /* header length is limited to 8 bits */ - io_sq->tx_max_header_size = - min_t(u32, ena_dev->tx_max_header_size, SZ_256); + io_sq->tx_max_header_size = min_t(u32, ena_dev->tx_max_header_size, SZ_256); ret = ena_com_init_io_sq(ena_dev, ctx, io_sq); if (ret) @@ -1938,8 +1872,7 @@ void ena_com_destroy_io_queue(struct ena_com_dev *ena_dev, u16 qid) struct ena_com_io_cq *io_cq; if (qid >= ENA_TOTAL_NUM_QUEUES) { - netdev_err(ena_dev->net_device, - "Qid (%d) is bigger than max num of queues (%d)\n", + netdev_err(ena_dev->net_device, "Qid (%d) is bigger than max num of queues (%d)\n", qid, ENA_TOTAL_NUM_QUEUES); return; } @@ -1983,8 +1916,7 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, if (rc) return rc; - if (get_resp.u.max_queue_ext.version != - ENA_FEATURE_MAX_QUEUE_EXT_VER) + if (get_resp.u.max_queue_ext.version != ENA_FEATURE_MAX_QUEUE_EXT_VER) return -EINVAL; memcpy(&get_feat_ctx->max_queue_ext, &get_resp.u.max_queue_ext, @@ -2025,18 +1957,15 @@ int ena_com_get_dev_attr_feat(struct ena_com_dev *ena_dev, rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_HW_HINTS, 0); if (!rc) - memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, - sizeof(get_resp.u.hw_hints)); + memcpy(&get_feat_ctx->hw_hints, &get_resp.u.hw_hints, sizeof(get_resp.u.hw_hints)); else if (rc == -EOPNOTSUPP) - memset(&get_feat_ctx->hw_hints, 0x0, - sizeof(get_feat_ctx->hw_hints)); + memset(&get_feat_ctx->hw_hints, 0x0, sizeof(get_feat_ctx->hw_hints)); else return rc; rc = ena_com_get_feature(ena_dev, &get_resp, ENA_ADMIN_LLQ, 0); if (!rc) - memcpy(&get_feat_ctx->llq, &get_resp.u.llq, - sizeof(get_resp.u.llq)); + memcpy(&get_feat_ctx->llq, &get_resp.u.llq, sizeof(get_resp.u.llq)); else if (rc == -EOPNOTSUPP) memset(&get_feat_ctx->llq, 0x0, sizeof(get_feat_ctx->llq)); else @@ -2084,8 +2013,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) aenq_common = &aenq_e->aenq_common_desc; /* Go over all the events */ - while ((READ_ONCE(aenq_common->flags) & - ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { + while ((READ_ONCE(aenq_common->flags) & ENA_ADMIN_AENQ_COMMON_DESC_PHASE_MASK) == phase) { /* Make sure the phase bit (ownership) is as expected before * reading the rest of the descriptor. */ @@ -2094,8 +2022,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) timestamp = (u64)aenq_common->timestamp_low | ((u64)aenq_common->timestamp_high << 32); - netdev_dbg(ena_dev->net_device, - "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", + netdev_dbg(ena_dev->net_device, "AENQ! Group[%x] Syndrome[%x] timestamp: [%llus]\n", aenq_common->group, aenq_common->syndrome, timestamp); /* Handle specific event*/ @@ -2124,8 +2051,7 @@ void ena_com_aenq_intr_handler(struct ena_com_dev *ena_dev, void *data) /* write the aenq doorbell after all AENQ descriptors were read */ mb(); - writel_relaxed((u32)aenq->head, - ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); + writel_relaxed((u32)aenq->head, ena_dev->reg_bar + ENA_REGS_AENQ_HEAD_DB_OFF); } int ena_com_dev_reset(struct ena_com_dev *ena_dev, @@ -2137,15 +2063,13 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, stat = ena_com_reg_bar_read32(ena_dev, ENA_REGS_DEV_STS_OFF); cap = ena_com_reg_bar_read32(ena_dev, ENA_REGS_CAPS_OFF); - if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || - (cap == ENA_MMIO_READ_TIMEOUT))) { + if (unlikely((stat == ENA_MMIO_READ_TIMEOUT) || (cap == ENA_MMIO_READ_TIMEOUT))) { netdev_err(ena_dev->net_device, "Reg read32 timeout occurred\n"); return -ETIME; } if ((stat & ENA_REGS_DEV_STS_READY_MASK) == 0) { - netdev_err(ena_dev->net_device, - "Device isn't ready, can't reset device\n"); + netdev_err(ena_dev->net_device, "Device isn't ready, can't reset device\n"); return -EINVAL; } @@ -2168,8 +2092,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, rc = wait_for_reset_state(ena_dev, timeout, ENA_REGS_DEV_STS_RESET_IN_PROGRESS_MASK); if (rc != 0) { - netdev_err(ena_dev->net_device, - "Reset indication didn't turn on\n"); + netdev_err(ena_dev->net_device, "Reset indication didn't turn on\n"); return rc; } @@ -2177,8 +2100,7 @@ int ena_com_dev_reset(struct ena_com_dev *ena_dev, writel(0, ena_dev->reg_bar + ENA_REGS_DEV_CTL_OFF); rc = wait_for_reset_state(ena_dev, timeout, 0); if (rc != 0) { - netdev_err(ena_dev->net_device, - "Reset indication didn't turn off\n"); + netdev_err(ena_dev->net_device, "Reset indication didn't turn off\n"); return rc; } @@ -2215,8 +2137,7 @@ static int ena_get_dev_stats(struct ena_com_dev *ena_dev, sizeof(*get_resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to get stats. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to get stats. error: %d\n", ret); return ret; } @@ -2228,8 +2149,7 @@ int ena_com_get_eni_stats(struct ena_com_dev *ena_dev, int ret; if (!ena_com_get_cap(ena_dev, ENA_ADMIN_ENI_STATS)) { - netdev_err(ena_dev->net_device, - "Capability %d isn't supported\n", + netdev_err(ena_dev->net_device, "Capability %d isn't supported\n", ENA_ADMIN_ENI_STATS); return -EOPNOTSUPP; } @@ -2266,8 +2186,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) int ret; if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_MTU)) { - netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", - ENA_ADMIN_MTU); + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_MTU); return -EOPNOTSUPP; } @@ -2286,8 +2205,7 @@ int ena_com_set_dev_mtu(struct ena_com_dev *ena_dev, u32 mtu) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set mtu %d. error: %d\n", mtu, ret); + netdev_err(ena_dev->net_device, "Failed to set mtu %d. error: %d\n", mtu, ret); return ret; } @@ -2301,8 +2219,7 @@ int ena_com_get_offload_settings(struct ena_com_dev *ena_dev, ret = ena_com_get_feature(ena_dev, &resp, ENA_ADMIN_STATELESS_OFFLOAD_CONFIG, 0); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to get offload capabilities %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to get offload capabilities %d\n", ret); return ret; } @@ -2320,8 +2237,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) struct ena_admin_get_feat_resp get_resp; int ret; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_FUNCTION)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_FUNCTION)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_FUNCTION); return -EOPNOTSUPP; @@ -2334,8 +2250,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) return ret; if (!(get_resp.u.flow_hash_func.supported_func & BIT(rss->hash_func))) { - netdev_err(ena_dev->net_device, - "Func hash %d isn't supported by device, abort\n", + netdev_err(ena_dev->net_device, "Func hash %d isn't supported by device, abort\n", rss->hash_func); return -EOPNOTSUPP; } @@ -2365,8 +2280,7 @@ int ena_com_set_hash_function(struct ena_com_dev *ena_dev) (struct ena_admin_acq_entry *)&resp, sizeof(resp)); if (unlikely(ret)) { - netdev_err(ena_dev->net_device, - "Failed to set hash function %d. error: %d\n", + netdev_err(ena_dev->net_device, "Failed to set hash function %d. error: %d\n", rss->hash_func, ret); return -EINVAL; } @@ -2398,16 +2312,15 @@ int ena_com_fill_hash_function(struct ena_com_dev *ena_dev, return rc; if (!(BIT(func) & get_resp.u.flow_hash_func.supported_func)) { - netdev_err(ena_dev->net_device, - "Flow hash function %d isn't supported\n", func); + netdev_err(ena_dev->net_device, "Flow hash function %d isn't supported\n", func); return -EOPNOTSUPP; } if ((func == ENA_ADMIN_TOEPLITZ) && key) { if (key_len != sizeof(hash_key->key)) { netdev_err(ena_dev->net_device, - "key len (%u) doesn't equal the supported size (%zu)\n", - key_len, sizeof(hash_key->key)); + "key len (%u) doesn't equal the supported size (%zu)\n", key_len, + sizeof(hash_key->key)); return -EINVAL; } memcpy(hash_key->key, key, key_len); @@ -2495,8 +2408,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) struct ena_admin_set_feat_resp resp; int ret; - if (!ena_com_check_supported_feature_id(ena_dev, - ENA_ADMIN_RSS_HASH_INPUT)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_HASH_INPUT)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_HASH_INPUT); return -EOPNOTSUPP; @@ -2527,8 +2439,7 @@ int ena_com_set_hash_ctrl(struct ena_com_dev *ena_dev) (struct ena_admin_acq_entry *)&resp, sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set hash input. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set hash input. error: %d\n", ret); return ret; } @@ -2605,8 +2516,7 @@ int ena_com_fill_hash_ctrl(struct ena_com_dev *ena_dev, int rc; if (proto >= ENA_ADMIN_RSS_PROTO_NUM) { - netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", - proto); + netdev_err(ena_dev->net_device, "Invalid proto num (%u)\n", proto); return -EINVAL; } @@ -2658,8 +2568,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) struct ena_admin_set_feat_resp resp; int ret; - if (!ena_com_check_supported_feature_id( - ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { + if (!ena_com_check_supported_feature_id(ena_dev, ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG)) { netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_RSS_INDIRECTION_TABLE_CONFIG); return -EOPNOTSUPP; @@ -2699,8 +2608,7 @@ int ena_com_indirect_table_set(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set indirect table. error: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set indirect table. error: %d\n", ret); return ret; } @@ -2779,9 +2687,8 @@ int ena_com_allocate_host_info(struct ena_com_dev *ena_dev) { struct ena_host_attribute *host_attr = &ena_dev->host_attr; - host_attr->host_info = - dma_alloc_coherent(ena_dev->dmadev, SZ_4K, - &host_attr->host_info_dma_addr, GFP_KERNEL); + host_attr->host_info = dma_alloc_coherent(ena_dev->dmadev, SZ_4K, + &host_attr->host_info_dma_addr, GFP_KERNEL); if (unlikely(!host_attr->host_info)) return -ENOMEM; @@ -2827,8 +2734,7 @@ void ena_com_delete_debug_area(struct ena_com_dev *ena_dev) if (host_attr->debug_area_virt_addr) { dma_free_coherent(ena_dev->dmadev, host_attr->debug_area_size, - host_attr->debug_area_virt_addr, - host_attr->debug_area_dma_addr); + host_attr->debug_area_virt_addr, host_attr->debug_area_dma_addr); host_attr->debug_area_virt_addr = NULL; } } @@ -2877,8 +2783,7 @@ int ena_com_set_host_attributes(struct ena_com_dev *ena_dev) sizeof(resp)); if (unlikely(ret)) - netdev_err(ena_dev->net_device, - "Failed to set host attributes: %d\n", ret); + netdev_err(ena_dev->net_device, "Failed to set host attributes: %d\n", ret); return ret; } @@ -2896,8 +2801,7 @@ static int ena_com_update_nonadaptive_moderation_interval(struct ena_com_dev *en u32 *intr_moder_interval) { if (!intr_delay_resolution) { - netdev_err(ena_dev->net_device, - "Illegal interrupt delay granularity value\n"); + netdev_err(ena_dev->net_device, "Illegal interrupt delay granularity value\n"); return -EFAULT; } @@ -2935,14 +2839,12 @@ int ena_com_init_interrupt_moderation(struct ena_com_dev *ena_dev) if (rc) { if (rc == -EOPNOTSUPP) { - netdev_dbg(ena_dev->net_device, - "Feature %d isn't supported\n", + netdev_dbg(ena_dev->net_device, "Feature %d isn't supported\n", ENA_ADMIN_INTERRUPT_MODERATION); rc = 0; } else { netdev_err(ena_dev->net_device, - "Failed to get interrupt moderation admin cmd. rc: %d\n", - rc); + "Failed to get interrupt moderation admin cmd. rc: %d\n", rc); } /* no moderation supported, disable adaptive support */ @@ -2990,8 +2892,7 @@ int ena_com_config_dev_mode(struct ena_com_dev *ena_dev, (llq_info->descs_num_before_header * sizeof(struct ena_eth_io_tx_desc)); if (unlikely(ena_dev->tx_max_header_size == 0)) { - netdev_err(ena_dev->net_device, - "The size of the LLQ entry is smaller than needed\n"); + netdev_err(ena_dev->net_device, "The size of the LLQ entry is smaller than needed\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/amazon/ena/ena_com.h b/drivers/net/ethernet/amazon/ena/ena_com.h index 3c5081d9d25d..fea57eb8e58b 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_com.h @@ -109,16 +109,13 @@ struct ena_com_io_cq { /* Interrupt unmask register */ u32 __iomem *unmask_reg; - /* The completion queue head doorbell register */ - u32 __iomem *cq_head_db_reg; - /* numa configuration register (for TPH) */ u32 __iomem *numa_node_cfg_reg; /* The value to write to the above register to unmask * the interrupt of this queue */ - u32 msix_vector; + u32 msix_vector ____cacheline_aligned; enum queue_direction direction; @@ -134,7 +131,6 @@ struct ena_com_io_cq { /* Device queue index */ u16 idx; u16 head; - u16 last_head_update; u8 phase; u8 cdesc_entry_size_in_bytes; @@ -158,7 +154,6 @@ struct ena_com_io_sq { struct ena_com_io_desc_addr desc_addr; u32 __iomem *db_addr; - u8 __iomem *header_addr; enum queue_direction direction; enum ena_admin_placement_policy_type mem_queue_type; diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.c b/drivers/net/ethernet/amazon/ena/ena_eth_com.c index f9f886289b97..933e619b3a31 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.c @@ -18,8 +18,7 @@ static struct ena_eth_io_rx_cdesc_base *ena_com_get_next_rx_cdesc( cdesc = (struct ena_eth_io_rx_cdesc_base *)(io_cq->cdesc_addr.virt_addr + (head_masked * io_cq->cdesc_entry_size_in_bytes)); - desc_phase = (READ_ONCE(cdesc->status) & - ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> + desc_phase = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_PHASE_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_PHASE_SHIFT; if (desc_phase != expected_phase) @@ -65,8 +64,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, io_sq->entries_in_tx_burst_left--; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Decreasing entries_in_tx_burst_left of queue %d to %d\n", - io_sq->qid, io_sq->entries_in_tx_burst_left); + "Decreasing entries_in_tx_burst_left of queue %d to %d\n", io_sq->qid, + io_sq->entries_in_tx_burst_left); } /* Make sure everything was written into the bounce buffer before @@ -75,8 +74,8 @@ static int ena_com_write_bounce_buffer_to_dev(struct ena_com_io_sq *io_sq, wmb(); /* The line is completed. Copy it to dev */ - __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, - bounce_buffer, (llq_info->desc_list_entry_size) / 8); + __iowrite64_copy(io_sq->desc_addr.pbuf_dev_addr + dst_offset, bounce_buffer, + (llq_info->desc_list_entry_size) / 8); io_sq->tail++; @@ -102,16 +101,14 @@ static int ena_com_write_header_to_bounce(struct ena_com_io_sq *io_sq, header_offset = llq_info->descs_num_before_header * io_sq->desc_entry_size; - if (unlikely((header_offset + header_len) > - llq_info->desc_list_entry_size)) { + if (unlikely((header_offset + header_len) > llq_info->desc_list_entry_size)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Trying to write header larger than llq entry can accommodate\n"); return -EFAULT; } if (unlikely(!bounce_buffer)) { - netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Bounce buffer is NULL\n"); + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); return -EFAULT; } @@ -129,8 +126,7 @@ static void *get_sq_desc_llq(struct ena_com_io_sq *io_sq) bounce_buffer = pkt_ctrl->curr_bounce_buf; if (unlikely(!bounce_buffer)) { - netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Bounce buffer is NULL\n"); + netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Bounce buffer is NULL\n"); return NULL; } @@ -247,8 +243,7 @@ static u16 ena_com_cdesc_rx_pkt_get(struct ena_com_io_cq *io_cq, ena_com_cq_inc_head(io_cq); count++; - last = (READ_ONCE(cdesc->status) & - ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> + last = (READ_ONCE(cdesc->status) & ENA_ETH_IO_RX_CDESC_BASE_LAST_MASK) >> ENA_ETH_IO_RX_CDESC_BASE_LAST_SHIFT; } while (!last); @@ -369,9 +364,8 @@ static void ena_com_rx_set_flags(struct ena_com_io_cq *io_cq, netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, "l3_proto %d l4_proto %d l3_csum_err %d l4_csum_err %d hash %d frag %d cdesc_status %x\n", - ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, - ena_rx_ctx->l3_csum_err, ena_rx_ctx->l4_csum_err, - ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); + ena_rx_ctx->l3_proto, ena_rx_ctx->l4_proto, ena_rx_ctx->l3_csum_err, + ena_rx_ctx->l4_csum_err, ena_rx_ctx->hash, ena_rx_ctx->frag, cdesc->status); } /*****************************************************************************/ @@ -403,13 +397,12 @@ int ena_com_prepare_tx(struct ena_com_io_sq *io_sq, if (unlikely(header_len > io_sq->tx_max_header_size)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Header size is too large %d max header: %d\n", - header_len, io_sq->tx_max_header_size); + "Header size is too large %d max header: %d\n", header_len, + io_sq->tx_max_header_size); return -EINVAL; } - if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && - !buffer_to_push)) { + if (unlikely(io_sq->mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV && !buffer_to_push)) { netdev_err(ena_com_io_sq_to_ena_dev(io_sq)->net_device, "Push header wasn't provided in LLQ mode\n"); return -EINVAL; @@ -556,13 +549,11 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, } netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, - nb_hw_desc); + "Fetch rx packet: queue %d completed desc: %d\n", io_cq->qid, nb_hw_desc); if (unlikely(nb_hw_desc > ena_rx_ctx->max_bufs)) { netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, - ena_rx_ctx->max_bufs); + "Too many RX cdescs (%d) > MAX(%d)\n", nb_hw_desc, ena_rx_ctx->max_bufs); return -ENOSPC; } @@ -586,8 +577,8 @@ int ena_com_rx_pkt(struct ena_com_io_cq *io_cq, io_sq->next_to_comp += nb_hw_desc; netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "[%s][QID#%d] Updating SQ head to: %d\n", __func__, - io_sq->qid, io_sq->next_to_comp); + "[%s][QID#%d] Updating SQ head to: %d\n", __func__, io_sq->qid, + io_sq->next_to_comp); /* Get rx flags from the last pkt */ ena_com_rx_set_flags(io_cq, ena_rx_ctx, cdesc); @@ -624,8 +615,8 @@ int ena_com_add_single_rx_desc(struct ena_com_io_sq *io_sq, desc->req_id = req_id; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", - __func__, io_sq->qid, req_id); + "[%s] Adding single RX desc, Queue: %u, req_id: %u\n", __func__, io_sq->qid, + req_id); desc->buff_addr_lo = (u32)ena_buf->paddr; desc->buff_addr_hi = diff --git a/drivers/net/ethernet/amazon/ena/ena_eth_com.h b/drivers/net/ethernet/amazon/ena/ena_eth_com.h index 372b259279ec..72b019758caa 100644 --- a/drivers/net/ethernet/amazon/ena/ena_eth_com.h +++ b/drivers/net/ethernet/amazon/ena/ena_eth_com.h @@ -8,8 +8,6 @@ #include "ena_com.h" -/* head update threshold in units of (queue size / ENA_COMP_HEAD_THRESH) */ -#define ENA_COMP_HEAD_THRESH 4 /* we allow 2 DMA descriptors per LLQ entry */ #define ENA_LLQ_ENTRY_DESC_CHUNK_SIZE (2 * sizeof(struct ena_eth_io_tx_desc)) #define ENA_LLQ_HEADER (128UL - ENA_LLQ_ENTRY_DESC_CHUNK_SIZE) @@ -145,8 +143,8 @@ static inline bool ena_com_is_doorbell_needed(struct ena_com_io_sq *io_sq, } netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Queue: %d num_descs: %d num_entries_needed: %d\n", - io_sq->qid, num_descs, num_entries_needed); + "Queue: %d num_descs: %d num_entries_needed: %d\n", io_sq->qid, num_descs, + num_entries_needed); return num_entries_needed > io_sq->entries_in_tx_burst_left; } @@ -157,43 +155,20 @@ static inline int ena_com_write_sq_doorbell(struct ena_com_io_sq *io_sq) u16 tail = io_sq->tail; netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Write submission queue doorbell for queue: %d tail: %d\n", - io_sq->qid, tail); + "Write submission queue doorbell for queue: %d tail: %d\n", io_sq->qid, tail); writel(tail, io_sq->db_addr); if (is_llq_max_tx_burst_exists(io_sq)) { netdev_dbg(ena_com_io_sq_to_ena_dev(io_sq)->net_device, - "Reset available entries in tx burst for queue %d to %d\n", - io_sq->qid, max_entries_in_tx_burst); + "Reset available entries in tx burst for queue %d to %d\n", io_sq->qid, + max_entries_in_tx_burst); io_sq->entries_in_tx_burst_left = max_entries_in_tx_burst; } return 0; } -static inline int ena_com_update_dev_comp_head(struct ena_com_io_cq *io_cq) -{ - u16 unreported_comp, head; - bool need_update; - - if (unlikely(io_cq->cq_head_db_reg)) { - head = io_cq->head; - unreported_comp = head - io_cq->last_head_update; - need_update = unreported_comp > (io_cq->q_depth / ENA_COMP_HEAD_THRESH); - - if (unlikely(need_update)) { - netdev_dbg(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Write completion queue doorbell for queue %d: head: %d\n", - io_cq->qid, head); - writel(head, io_cq->cq_head_db_reg); - io_cq->last_head_update = head; - } - } - - return 0; -} - static inline void ena_com_update_numa_node(struct ena_com_io_cq *io_cq, u8 numa_node) { @@ -248,8 +223,8 @@ static inline int ena_com_tx_comp_req_id_get(struct ena_com_io_cq *io_cq, *req_id = READ_ONCE(cdesc->req_id); if (unlikely(*req_id >= io_cq->q_depth)) { - netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, - "Invalid req id %d\n", cdesc->req_id); + netdev_err(ena_com_io_cq_to_ena_dev(io_cq)->net_device, "Invalid req id %d\n", + cdesc->req_id); return -EINVAL; } diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index 1c0a7828d397..03be2c008c4d 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -32,7 +32,7 @@ MODULE_LICENSE("GPL"); #define ENA_MAX_RINGS min_t(unsigned int, ENA_MAX_NUM_IO_QUEUES, num_possible_cpus()) #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_IFUP | \ - NETIF_MSG_TX_DONE | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) + NETIF_MSG_IFDOWN | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR) static struct ena_aenq_handlers aenq_handlers; @@ -47,19 +47,44 @@ static int ena_restore_device(struct ena_adapter *adapter); static void ena_tx_timeout(struct net_device *dev, unsigned int txqueue) { + enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_OS_NETDEV_WD; struct ena_adapter *adapter = netdev_priv(dev); + unsigned int time_since_last_napi, threshold; + struct ena_ring *tx_ring; + int napi_scheduled; + + if (txqueue >= adapter->num_io_queues) { + netdev_err(dev, "TX timeout on invalid queue %u\n", txqueue); + goto schedule_reset; + } + + threshold = jiffies_to_usecs(dev->watchdog_timeo); + tx_ring = &adapter->tx_ring[txqueue]; + + time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); + napi_scheduled = !!(tx_ring->napi->state & NAPIF_STATE_SCHED); + + netdev_err(dev, + "TX q %d is paused for too long (threshold %u). Time since last napi %u usec. napi scheduled: %d\n", + txqueue, + threshold, + time_since_last_napi, + napi_scheduled); + if (threshold < time_since_last_napi && napi_scheduled) { + netdev_err(dev, + "napi handler hasn't been called for a long time but is scheduled\n"); + reset_reason = ENA_REGS_RESET_SUSPECTED_POLL_STARVATION; + } +schedule_reset: /* Change the state of the device to trigger reset * Check that we are not in the middle or a trigger already */ - if (test_and_set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) return; - ena_reset_device(adapter, ENA_REGS_RESET_OS_NETDEV_WD); + ena_reset_device(adapter, reset_reason); ena_increase_stat(&adapter->dev_stats.tx_timeout, 1, &adapter->syncp); - - netif_err(adapter, tx_err, dev, "Transmit time out\n"); } static void update_rx_ring_mtu(struct ena_adapter *adapter, int mtu) @@ -116,11 +141,9 @@ int ena_xmit_common(struct ena_adapter *adapter, if (unlikely(rc)) { netif_err(adapter, tx_queued, adapter->netdev, "Failed to prepare tx bufs\n"); - ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, - &ring->syncp); + ena_increase_stat(&ring->tx_stats.prepare_ctx_err, 1, &ring->syncp); if (rc != -ENOMEM) - ena_reset_device(adapter, - ENA_REGS_RESET_DRIVER_INVALID_STATE); + ena_reset_device(adapter, ENA_REGS_RESET_DRIVER_INVALID_STATE); return rc; } @@ -485,8 +508,7 @@ static struct page *ena_alloc_map_page(struct ena_ring *rx_ring, */ page = dev_alloc_page(); if (!page) { - ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, - &rx_ring->syncp); + ena_increase_stat(&rx_ring->rx_stats.page_alloc_fail, 1, &rx_ring->syncp); return ERR_PTR(-ENOSPC); } @@ -545,8 +567,8 @@ static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info, unsigned long attrs) { - dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, - DMA_BIDIRECTIONAL, attrs); + dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL, + attrs); } static void ena_free_rx_page(struct ena_ring *rx_ring, @@ -819,8 +841,7 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) &req_id); if (rc) { if (unlikely(rc == -EINVAL)) - handle_invalid_req_id(tx_ring, req_id, NULL, - false); + handle_invalid_req_id(tx_ring, req_id, NULL, false); break; } @@ -856,7 +877,6 @@ static int ena_clean_tx_irq(struct ena_ring *tx_ring, u32 budget) tx_ring->next_to_clean = next_to_clean; ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done); - ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq); netdev_tx_completed_queue(txq, tx_pkts, tx_bytes); @@ -1046,8 +1066,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring, DMA_FROM_DEVICE); if (!reuse_rx_buf_page) - ena_unmap_rx_buff_attrs(rx_ring, rx_info, - DMA_ATTR_SKIP_CPU_SYNC); + ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC); skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, rx_info->page, page_offset + buf_offset, len, buf_len); @@ -1303,10 +1322,8 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, ENA_RX_REFILL_THRESH_PACKET); /* Optimization, try to batch new rx buffers */ - if (refill_required > refill_threshold) { - ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq); + if (refill_required > refill_threshold) ena_refill_rx_bufs(rx_ring, refill_required); - } if (xdp_flags & ENA_XDP_REDIRECT) xdp_do_flush(); @@ -1320,8 +1337,7 @@ error: adapter = netdev_priv(rx_ring->netdev); if (rc == -ENOSPC) { - ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, - &rx_ring->syncp); + ena_increase_stat(&rx_ring->rx_stats.bad_desc_num, 1, &rx_ring->syncp); ena_reset_device(adapter, ENA_REGS_RESET_TOO_MANY_RX_DESCS); } else { ena_increase_stat(&rx_ring->rx_stats.bad_req_id, 1, @@ -1811,8 +1827,7 @@ static int ena_rss_configure(struct ena_adapter *adapter) if (!ena_dev->rss.tbl_log_size) { rc = ena_rss_init_default(adapter); if (rc && (rc != -EOPNOTSUPP)) { - netif_err(adapter, ifup, adapter->netdev, - "Failed to init RSS rc: %d\n", rc); + netif_err(adapter, ifup, adapter->netdev, "Failed to init RSS rc: %d\n", rc); return rc; } } @@ -2134,6 +2149,12 @@ int ena_up(struct ena_adapter *adapter) */ ena_init_napi_in_range(adapter, 0, io_queue_count); + /* Enabling DIM needs to happen before enabling IRQs since DIM + * is run from napi routine + */ + if (ena_com_interrupt_moderation_supported(adapter->ena_dev)) + ena_com_enable_adaptive_moderation(adapter->ena_dev); + rc = ena_request_io_irq(adapter); if (rc) goto err_req_irq; @@ -2184,7 +2205,7 @@ void ena_down(struct ena_adapter *adapter) { int io_queue_count = adapter->num_io_queues + adapter->xdp_num_queues; - netif_info(adapter, ifdown, adapter->netdev, "%s\n", __func__); + netif_dbg(adapter, ifdown, adapter->netdev, "%s\n", __func__); clear_bit(ENA_FLAG_DEV_UP, &adapter->flags); @@ -2197,8 +2218,6 @@ void ena_down(struct ena_adapter *adapter) /* After this point the napi handler won't enable the tx queue */ ena_napi_disable_in_range(adapter, 0, io_queue_count); - /* After destroy the queue there won't be any new interrupts */ - if (test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags)) { int rc; @@ -2588,8 +2607,6 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(rc)) goto error_drop_packet; - skb_tx_timestamp(skb); - next_to_use = tx_ring->next_to_use; req_id = tx_ring->free_ids[next_to_use]; tx_info = &tx_ring->tx_buffer_info[req_id]; @@ -2653,6 +2670,8 @@ static netdev_tx_t ena_start_xmit(struct sk_buff *skb, struct net_device *dev) } } + skb_tx_timestamp(skb); + if (netif_xmit_stopped(txq) || !netdev_xmit_more()) /* trigger the dma engine. ena_ring_tx_doorbell() * calls a memory barrier inside it. @@ -2764,8 +2783,7 @@ static void ena_config_debug_area(struct ena_adapter *adapter) rc = ena_com_set_host_attributes(adapter->ena_dev); if (rc) { if (rc == -EOPNOTSUPP) - netif_warn(adapter, drv, adapter->netdev, - "Cannot set host attributes\n"); + netif_warn(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); else netif_err(adapter, drv, adapter->netdev, "Cannot set host attributes\n"); @@ -2873,8 +2891,8 @@ static const struct net_device_ops ena_netdev_ops = { .ndo_xdp_xmit = ena_xdp_xmit, }; -static void ena_calc_io_queue_size(struct ena_adapter *adapter, - struct ena_com_dev_get_features_ctx *get_feat_ctx) +static int ena_calc_io_queue_size(struct ena_adapter *adapter, + struct ena_com_dev_get_features_ctx *get_feat_ctx) { struct ena_admin_feature_llq_desc *llq = &get_feat_ctx->llq; struct ena_com_dev *ena_dev = adapter->ena_dev; @@ -2933,6 +2951,18 @@ static void ena_calc_io_queue_size(struct ena_adapter *adapter, max_tx_queue_size = rounddown_pow_of_two(max_tx_queue_size); max_rx_queue_size = rounddown_pow_of_two(max_rx_queue_size); + if (max_tx_queue_size < ENA_MIN_RING_SIZE) { + netdev_err(adapter->netdev, "Device max TX queue size: %d < minimum: %d\n", + max_tx_queue_size, ENA_MIN_RING_SIZE); + return -EINVAL; + } + + if (max_rx_queue_size < ENA_MIN_RING_SIZE) { + netdev_err(adapter->netdev, "Device max RX queue size: %d < minimum: %d\n", + max_rx_queue_size, ENA_MIN_RING_SIZE); + return -EINVAL; + } + /* When forcing large headers, we multiply the entry size by 2, and therefore divide * the queue size by 2, leaving the amount of memory used by the queues unchanged. */ @@ -2963,6 +2993,8 @@ static void ena_calc_io_queue_size(struct ena_adapter *adapter, adapter->max_rx_ring_size = max_rx_queue_size; adapter->requested_tx_ring_size = tx_queue_size; adapter->requested_rx_ring_size = rx_queue_size; + + return 0; } static int ena_device_validate_params(struct ena_adapter *adapter, @@ -3070,6 +3102,7 @@ static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev, bool *wd_state) { struct ena_com_dev *ena_dev = adapter->ena_dev; + struct net_device *netdev = adapter->netdev; struct ena_llq_configurations llq_config; struct device *dev = &pdev->dev; bool readless_supported; @@ -3159,15 +3192,19 @@ static int ena_device_init(struct ena_adapter *adapter, struct pci_dev *pdev, rc = ena_set_queues_placement_policy(pdev, ena_dev, &get_feat_ctx->llq, &llq_config); if (rc) { - dev_err(dev, "ENA device init failed\n"); + netdev_err(netdev, "Cannot set queues placement policy rc= %d\n", rc); goto err_admin_init; } - ena_calc_io_queue_size(adapter, get_feat_ctx); + rc = ena_calc_io_queue_size(adapter, get_feat_ctx); + if (unlikely(rc)) + goto err_admin_init; return 0; err_admin_init: + ena_com_abort_admin_commands(ena_dev); + ena_com_wait_for_abort_completion(ena_dev); ena_com_delete_host_info(ena_dev); ena_com_admin_destroy(ena_dev); err_mmio_read_less: @@ -3226,7 +3263,7 @@ static void ena_destroy_device(struct ena_adapter *adapter, bool graceful) if (!graceful) ena_com_set_admin_running_state(ena_dev, false); - if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) + if (dev_up) ena_down(adapter); /* Stop the device from sending AENQ events (in case reset flag is set @@ -3372,14 +3409,18 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter, struct ena_ring *tx_ring) { struct ena_napi *ena_napi = container_of(tx_ring->napi, struct ena_napi, napi); + enum ena_regs_reset_reason_types reset_reason = ENA_REGS_RESET_MISS_TX_CMPL; unsigned int time_since_last_napi; unsigned int missing_tx_comp_to; bool is_tx_comp_time_expired; struct ena_tx_buffer *tx_buf; unsigned long last_jiffies; + int napi_scheduled; u32 missed_tx = 0; int i, rc = 0; + missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to); + for (i = 0; i < tx_ring->ring_size; i++) { tx_buf = &tx_ring->tx_buffer_info[i]; last_jiffies = tx_buf->last_jiffies; @@ -3406,25 +3447,45 @@ static int check_missing_comp_in_tx_queue(struct ena_adapter *adapter, adapter->missing_tx_completion_to); if (unlikely(is_tx_comp_time_expired)) { - if (!tx_buf->print_once) { - time_since_last_napi = jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); - missing_tx_comp_to = jiffies_to_msecs(adapter->missing_tx_completion_to); - netif_notice(adapter, tx_err, adapter->netdev, - "Found a Tx that wasn't completed on time, qid %d, index %d. %u usecs have passed since last napi execution. Missing Tx timeout value %u msecs\n", - tx_ring->qid, i, time_since_last_napi, missing_tx_comp_to); + time_since_last_napi = + jiffies_to_usecs(jiffies - tx_ring->tx_stats.last_napi_jiffies); + napi_scheduled = !!(ena_napi->napi.state & NAPIF_STATE_SCHED); + + if (missing_tx_comp_to < time_since_last_napi && napi_scheduled) { + /* We suspect napi isn't called because the + * bottom half is not run. Require a bigger + * timeout for these cases + */ + if (!time_is_before_jiffies(last_jiffies + + 2 * adapter->missing_tx_completion_to)) + continue; + + reset_reason = ENA_REGS_RESET_SUSPECTED_POLL_STARVATION; } - tx_buf->print_once = 1; missed_tx++; + + if (tx_buf->print_once) + continue; + + netif_notice(adapter, tx_err, adapter->netdev, + "TX hasn't completed, qid %d, index %d. %u usecs from last napi execution, napi scheduled: %d\n", + tx_ring->qid, i, time_since_last_napi, napi_scheduled); + + tx_buf->print_once = 1; } } if (unlikely(missed_tx > adapter->missing_tx_completion_threshold)) { netif_err(adapter, tx_err, adapter->netdev, - "The number of lost tx completions is above the threshold (%d > %d). Reset the device\n", + "Lost TX completions are above the threshold (%d > %d). Completion transmission timeout: %u.\n", missed_tx, - adapter->missing_tx_completion_threshold); - ena_reset_device(adapter, ENA_REGS_RESET_MISS_TX_CMPL); + adapter->missing_tx_completion_threshold, + missing_tx_comp_to); + netif_err(adapter, tx_err, adapter->netdev, + "Resetting the device\n"); + + ena_reset_device(adapter, reset_reason); rc = -EIO; } @@ -3762,8 +3823,8 @@ static int ena_rss_init_default(struct ena_adapter *adapter) } } - rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, - ENA_HASH_KEY_SIZE, 0xFFFFFFFF); + rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, NULL, ENA_HASH_KEY_SIZE, + 0xFFFFFFFF); if (unlikely(rc && (rc != -EOPNOTSUPP))) { dev_err(dev, "Cannot fill hash function\n"); goto err_fill_indir; @@ -4040,8 +4101,8 @@ static void __ena_shutoff(struct pci_dev *pdev, bool shutdown) free_irq_cpu_rmap(netdev->rx_cpu_rmap); netdev->rx_cpu_rmap = NULL; } -#endif /* CONFIG_RFS_ACCEL */ +#endif /* CONFIG_RFS_ACCEL */ /* Make sure timer and reset routine won't be called after * freeing device resources. */ diff --git a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h index 1e007a41a525..2c3d6a77ea79 100644 --- a/drivers/net/ethernet/amazon/ena/ena_regs_defs.h +++ b/drivers/net/ethernet/amazon/ena/ena_regs_defs.h @@ -21,6 +21,7 @@ enum ena_regs_reset_reason_types { ENA_REGS_RESET_USER_TRIGGER = 12, ENA_REGS_RESET_GENERIC = 13, ENA_REGS_RESET_MISS_INTERRUPT = 14, + ENA_REGS_RESET_SUSPECTED_POLL_STARVATION = 15, }; /* ena_registers offsets */ diff --git a/drivers/net/ethernet/amazon/ena/ena_xdp.c b/drivers/net/ethernet/amazon/ena/ena_xdp.c index fc1c4ef73ba3..337c435d3ce9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_xdp.c +++ b/drivers/net/ethernet/amazon/ena/ena_xdp.c @@ -412,7 +412,6 @@ static int ena_clean_xdp_irq(struct ena_ring *tx_ring, u32 budget) tx_ring->next_to_clean = next_to_clean; ena_com_comp_ack(tx_ring->ena_com_io_sq, total_done); - ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq); netif_dbg(tx_ring->adapter, tx_done, tx_ring->netdev, "tx_poll: q %d done. total pkts: %d\n", diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c index 18a6c8d99fa0..0bd1a0a1ae6a 100644 --- a/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c +++ b/drivers/net/ethernet/aquantia/atlantic/aq_ethtool.c @@ -697,7 +697,7 @@ static u32 eee_mask_to_ethtool_mask(u32 speed) return rate; } -static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) +static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_keee *eee) { struct aq_nic_s *aq_nic = netdev_priv(ndev); u32 rate, supported_rates; @@ -713,14 +713,14 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) if (err < 0) return err; - eee->supported = eee_mask_to_ethtool_mask(supported_rates); + eee->supported_u32 = eee_mask_to_ethtool_mask(supported_rates); if (aq_nic->aq_nic_cfg.eee_speeds) - eee->advertised = eee->supported; + eee->advertised_u32 = eee->supported_u32; - eee->lp_advertised = eee_mask_to_ethtool_mask(rate); + eee->lp_advertised_u32 = eee_mask_to_ethtool_mask(rate); - eee->eee_enabled = !!eee->advertised; + eee->eee_enabled = !!eee->advertised_u32; eee->tx_lpi_enabled = eee->eee_enabled; if ((supported_rates & rate) & AQ_NIC_RATE_EEE_MSK) @@ -729,7 +729,7 @@ static int aq_ethtool_get_eee(struct net_device *ndev, struct ethtool_eee *eee) return 0; } -static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_eee *eee) +static int aq_ethtool_set_eee(struct net_device *ndev, struct ethtool_keee *eee) { struct aq_nic_s *aq_nic = netdev_priv(ndev); u32 rate, supported_rates; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index ec90add6b03e..312bf9b6576e 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -337,7 +337,7 @@ struct bcmasp_intf { int wol_irq; unsigned int wol_irq_enabled:1; - struct ethtool_eee eee; + struct ethtool_keee eee; }; #define NUM_NET_FILTERS 32 diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index ce6a3d56fb23..2851bed153e6 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -363,10 +363,10 @@ void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable) intf->eee.eee_active = enable; } -static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; + struct ethtool_keee *p = &intf->eee; if (!dev->phydev) return -ENODEV; @@ -379,10 +379,10 @@ static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) return phy_ethtool_get_eee(dev->phydev, e); } -static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; + struct ethtool_keee *p = &intf->eee; int ret; if (!dev->phydev) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e9c1e1bb5580..528441b28c4e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -147,10 +147,11 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len) phy_fw_ver[0] = '\0'; bnx2x_get_ext_phy_fw_version(&bp->link_params, - phy_fw_ver, PHY_FW_VER_LEN); - strscpy(buf, bp->fw_ver, buf_len); - snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver), - "bc %d.%d.%d%s%s", + phy_fw_ver, sizeof(phy_fw_ver)); + /* This may become truncated. */ + scnprintf(buf, buf_len, + "%sbc %d.%d.%d%s%s", + bp->fw_ver, (bp->common.bc_ver & 0xff0000) >> 16, (bp->common.bc_ver & 0xff00) >> 8, (bp->common.bc_ver & 0xff), diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 81d232e6d05f..5f0e1759d078 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1132,7 +1132,7 @@ static void bnx2x_get_drvinfo(struct net_device *dev, } memset(version, 0, sizeof(version)); - bnx2x_fill_fw_str(bp, version, ETHTOOL_FWVERS_LEN); + bnx2x_fill_fw_str(bp, version, sizeof(version)); strlcat(info->fw_version, version, sizeof(info->fw_version)); strscpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); @@ -2108,7 +2108,7 @@ static u32 bnx2x_adv_to_eee(u32 modes, u32 shift) return eee_adv << shift; } -static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnx2x_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnx2x *bp = netdev_priv(dev); u32 eee_cfg; @@ -2120,14 +2120,14 @@ static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) eee_cfg = bp->link_vars.eee_status; - edata->supported = + edata->supported_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_SUPPORTED_MASK) >> SHMEM_EEE_SUPPORTED_SHIFT); - edata->advertised = + edata->advertised_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_ADV_STATUS_MASK) >> SHMEM_EEE_ADV_STATUS_SHIFT); - edata->lp_advertised = + edata->lp_advertised_u32 = bnx2x_eee_to_adv((eee_cfg & SHMEM_EEE_LP_ADV_STATUS_MASK) >> SHMEM_EEE_LP_ADV_STATUS_SHIFT); @@ -2141,7 +2141,7 @@ static int bnx2x_get_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnx2x_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnx2x *bp = netdev_priv(dev); u32 eee_cfg; @@ -2162,7 +2162,7 @@ static int bnx2x_set_eee(struct net_device *dev, struct ethtool_eee *edata) return -EOPNOTSUPP; } - advertised = bnx2x_adv_to_eee(edata->advertised, + advertised = bnx2x_adv_to_eee(edata->advertised_u32, SHMEM_EEE_ADV_STATUS_SHIFT); if ((advertised != (eee_cfg & SHMEM_EEE_ADV_STATUS_MASK))) { DP(BNX2X_MSG_ETHTOOL, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 02808513ffe4..ea310057fe3a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -6163,8 +6163,8 @@ static void bnx2x_link_int_ack(struct link_params *params, static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) { - str[0] = '\0'; - (*len)--; + if (*len) + str[0] = '\0'; return 0; } @@ -6173,7 +6173,7 @@ static int bnx2x_format_ver(u32 num, u8 *str, u16 *len) u16 ret; if (*len < 10) { - /* Need more than 10chars for this format */ + /* Need more than 10 chars for this format */ bnx2x_null_format_ver(num, str, len); return -EINVAL; } @@ -6188,8 +6188,8 @@ static int bnx2x_3_seq_format_ver(u32 num, u8 *str, u16 *len) { u16 ret; - if (*len < 10) { - /* Need more than 10chars for this format */ + if (*len < 9) { + /* Need more than 9 chars for this format */ bnx2x_null_format_ver(num, str, len); return -EINVAL; } @@ -6208,7 +6208,7 @@ int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 *version, int status = 0; u8 *ver_p = version; u16 remain_len = len; - if (version == NULL || params == NULL) + if (version == NULL || params == NULL || len == 0) return -EINVAL; bp = params->bp; @@ -11546,7 +11546,7 @@ static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len) str[2] = (spirom_ver & 0xFF0000) >> 16; str[3] = (spirom_ver & 0xFF000000) >> 24; str[4] = '\0'; - *len -= 5; + *len -= 4; return 0; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 39845d556baf..fde32b32fa81 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -10621,10 +10621,10 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) bp->phy_flags = resp->flags | (le16_to_cpu(resp->flags2) << 8); if (resp->flags & PORT_PHY_QCAPS_RESP_FLAGS_EEE_SUPPORTED) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode); - eee->supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + eee->supported_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); bp->lpi_tmr_lo = le32_to_cpu(resp->tx_lpi_timer_low) & PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_LOW_MASK; bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) & @@ -10766,7 +10766,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) link_info->module_status = resp->module_status; if (bp->phy_flags & BNXT_PHY_FL_EEE_CAP) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; u16 fw_speeds; eee->eee_active = 0; @@ -10775,7 +10775,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_active = 1; fw_speeds = le16_to_cpu( resp->link_partner_adv_eee_link_speed_mask); - eee->lp_advertised = + eee->lp_advertised_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); } @@ -10786,7 +10786,7 @@ int bnxt_update_link(struct bnxt *bp, bool chng_link_state) eee->eee_enabled = 1; fw_speeds = le16_to_cpu(resp->adv_eee_link_speed_mask); - eee->advertised = + eee->advertised_u32 = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); if (resp->eee_config_phy_addr & @@ -10957,7 +10957,7 @@ int bnxt_hwrm_set_pause(struct bnxt *bp) static void bnxt_hwrm_set_eee(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; if (eee->eee_enabled) { u16 eee_speeds; @@ -10969,7 +10969,7 @@ static void bnxt_hwrm_set_eee(struct bnxt *bp, flags |= PORT_PHY_CFG_REQ_FLAGS_EEE_TX_LPI_DISABLE; req->flags |= cpu_to_le32(flags); - eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised); + eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised_u32); req->eee_link_speed_mask = cpu_to_le16(eee_speeds); req->tx_lpi_timer = cpu_to_le32(eee->tx_lpi_timer); } else { @@ -11322,7 +11322,7 @@ static void bnxt_get_wol_settings(struct bnxt *bp) static bool bnxt_eee_config_ok(struct bnxt *bp) { - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; struct bnxt_link_info *link_info = &bp->link_info; if (!(bp->phy_flags & BNXT_PHY_FL_EEE_CAP)) @@ -11336,8 +11336,8 @@ static bool bnxt_eee_config_ok(struct bnxt *bp) eee->eee_enabled = 0; return false; } - if (eee->advertised & ~advertising) { - eee->advertised = advertising & eee->supported; + if (eee->advertised_u32 & ~advertising) { + eee->advertised_u32 = advertising & eee->supported_u32; return false; } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 47338b48ca20..b2cb3e77559d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2442,7 +2442,7 @@ struct bnxt { */ struct mutex link_lock; struct bnxt_link_info link_info; - struct ethtool_eee eee; + struct ethtool_keee eee; u32 lpi_tmr_lo; u32 lpi_tmr_hi; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index dc4ca706b0e2..481b835a7703 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3884,10 +3884,10 @@ static int bnxt_set_eeprom(struct net_device *dev, eeprom->len); } -static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnxt_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnxt *bp = netdev_priv(dev); - struct ethtool_eee *eee = &bp->eee; + struct ethtool_keee *eee = &bp->eee; struct bnxt_link_info *link_info = &bp->link_info; u32 advertising; int rc = 0; @@ -3919,16 +3919,16 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) edata->tx_lpi_timer = eee->tx_lpi_timer; } } - if (!edata->advertised) { - edata->advertised = advertising & eee->supported; - } else if (edata->advertised & ~advertising) { + if (!edata->advertised_u32) { + edata->advertised_u32 = advertising & eee->supported_u32; + } else if (edata->advertised_u32 & ~advertising) { netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n", - edata->advertised, advertising); + edata->advertised_u32, advertising); rc = -EINVAL; goto eee_exit; } - eee->advertised = edata->advertised; + eee->advertised_u32 = edata->advertised_u32; eee->tx_lpi_enabled = edata->tx_lpi_enabled; eee->tx_lpi_timer = edata->tx_lpi_timer; eee_ok: @@ -3942,7 +3942,7 @@ eee_exit: return rc; } -static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int bnxt_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct bnxt *bp = netdev_priv(dev); @@ -3954,12 +3954,12 @@ static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata) /* Preserve tx_lpi_timer so that the last value will be used * by default when it is re-enabled. */ - edata->advertised = 0; + edata->advertised_u32 = 0; edata->tx_lpi_enabled = 0; } if (!bp->eee.eee_active) - edata->lp_advertised = 0; + edata->lp_advertised_u32 = 0; return 0; } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 2d7ae71287b1..051c31fb17c2 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1317,10 +1317,10 @@ void bcmgenet_eee_enable_set(struct net_device *dev, bool enable, priv->eee.tx_lpi_enabled = tx_lpi_enabled; } -static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); - struct ethtool_eee *p = &priv->eee; + struct ethtool_keee *p = &priv->eee; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; @@ -1336,10 +1336,10 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e) return phy_ethtool_get_eee(dev->phydev, e); } -static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_keee *e) { struct bcmgenet_priv *priv = netdev_priv(dev); - struct ethtool_eee *p = &priv->eee; + struct ethtool_keee *p = &priv->eee; if (GENET_IS_V1(priv)) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 1985c0ec4da2..7523b60b3c1c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -645,7 +645,7 @@ struct bcmgenet_priv { struct bcmgenet_mib_counters mib; - struct ethtool_eee eee; + struct ethtool_keee eee; }; #define GENET_IO_MACRO(name, offset) \ diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 04964bbe08cf..f644a91317c9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2338,10 +2338,10 @@ static void tg3_phy_apply_otp(struct tg3 *tp) tg3_phy_toggle_auxctl_smdsp(tp, false); } -static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee) +static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_keee *eee) { u32 val; - struct ethtool_eee *dest = &tp->eee; + struct ethtool_keee *dest = &tp->eee; if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) return; @@ -2362,13 +2362,13 @@ static void tg3_eee_pull_config(struct tg3 *tp, struct ethtool_eee *eee) /* Pull lp advertised settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE, &val)) return; - dest->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + dest->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Pull advertised and eee_enabled settings */ if (tg3_phy_cl45_read(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, &val)) return; dest->eee_enabled = !!val; - dest->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + dest->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Pull tx_lpi_enabled */ val = tr32(TG3_CPMU_EEE_MODE); @@ -4364,9 +4364,9 @@ static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl) if (!tp->eee.eee_enabled) { val = 0; - tp->eee.advertised = 0; + tp->eee.advertised_u32 = 0; } else { - tp->eee.advertised = advertise & + tp->eee.advertised_u32 = advertise & (ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full); } @@ -4618,7 +4618,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp) static bool tg3_phy_eee_config_ok(struct tg3 *tp) { - struct ethtool_eee eee; + struct ethtool_keee eee; if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) return true; @@ -4626,13 +4626,13 @@ static bool tg3_phy_eee_config_ok(struct tg3 *tp) tg3_eee_pull_config(tp, &eee); if (tp->eee.eee_enabled) { - if (tp->eee.advertised != eee.advertised || + if (tp->eee.advertised_u32 != eee.advertised_u32 || tp->eee.tx_lpi_timer != eee.tx_lpi_timer || tp->eee.tx_lpi_enabled != eee.tx_lpi_enabled) return false; } else { /* EEE is disabled but we're advertising */ - if (eee.advertised) + if (eee.advertised_u32) return false; } @@ -14180,7 +14180,7 @@ static int tg3_set_coalesce(struct net_device *dev, return 0; } -static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int tg3_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct tg3 *tp = netdev_priv(dev); @@ -14189,7 +14189,7 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata) return -EOPNOTSUPP; } - if (edata->advertised != tp->eee.advertised) { + if (edata->advertised_u32 != tp->eee.advertised_u32) { netdev_warn(tp->dev, "Direct manipulation of EEE advertisement is not supported\n"); return -EINVAL; @@ -14217,7 +14217,7 @@ static int tg3_set_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int tg3_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int tg3_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct tg3 *tp = netdev_priv(dev); @@ -15655,10 +15655,10 @@ static int tg3_phy_probe(struct tg3 *tp) tg3_chip_rev_id(tp) != CHIPREV_ID_57765_A0))) { tp->phy_flags |= TG3_PHYFLG_EEE_CAP; - tp->eee.supported = SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full; - tp->eee.advertised = ADVERTISED_100baseT_Full | - ADVERTISED_1000baseT_Full; + tp->eee.supported_u32 = SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full; + tp->eee.advertised_u32 = ADVERTISED_100baseT_Full | + ADVERTISED_1000baseT_Full; tp->eee.eee_enabled = 1; tp->eee.tx_lpi_enabled = 1; tp->eee.tx_lpi_timer = TG3_CPMU_DBTMR1_LNKIDLE_2047US; diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 5016475e5005..cf1b2b123c7e 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -3419,7 +3419,7 @@ struct tg3 { unsigned int irq_cnt; struct ethtool_coalesce coal; - struct ethtool_eee eee; + struct ethtool_keee eee; /* firmware info */ const char *fw_needed; diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c index c2c5c589a5e3..44af1d13d931 100644 --- a/drivers/net/ethernet/ec_bhf.c +++ b/drivers/net/ethernet/ec_bhf.c @@ -590,5 +590,6 @@ module_pci_driver(pci_driver); module_param(polling_frequency, long, 0444); MODULE_PARM_DESC(polling_frequency, "Polling timer frequency in ns"); +MODULE_DESCRIPTION("Beckhoff CX5020 EtherCAT Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dariusz Marcinkiewicz <reksio@newterm.pl>"); diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index 9aeff2b37a61..eb64118f5b18 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -229,8 +229,10 @@ static int tsnep_phy_loopback(struct tsnep_adapter *adapter, bool enable) * would delay a working loopback anyway, let's ensure that loopback * is working immediately by setting link mode directly */ - if (!retval && enable) + if (!retval && enable) { + netif_carrier_on(adapter->netdev); tsnep_set_link_mode(adapter); + } return retval; } @@ -238,7 +240,7 @@ static int tsnep_phy_loopback(struct tsnep_adapter *adapter, bool enable) static int tsnep_phy_open(struct tsnep_adapter *adapter) { struct phy_device *phydev; - struct ethtool_eee ethtool_eee; + struct ethtool_keee ethtool_keee; int retval; retval = phy_connect_direct(adapter->netdev, adapter->phydev, @@ -257,8 +259,8 @@ static int tsnep_phy_open(struct tsnep_adapter *adapter) phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); /* disable EEE autoneg, EEE not supported by TSNEP */ - memset(ðtool_eee, 0, sizeof(ethtool_eee)); - phy_ethtool_set_eee(adapter->phydev, ðtool_eee); + memset(ðtool_keee, 0, sizeof(ethtool_keee)); + phy_ethtool_set_eee(adapter->phydev, ðtool_keee); adapter->phydev->irq = PHY_MAC_INTERRUPT; phy_start(adapter->phydev); diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index bfdbdab443ae..9f07f4947b63 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2402,7 +2402,7 @@ static void enetc_clear_interrupts(struct enetc_ndev_priv *priv) static int enetc_phylink_connect(struct net_device *ndev) { struct enetc_ndev_priv *priv = netdev_priv(ndev); - struct ethtool_eee edata; + struct ethtool_keee edata; int err; if (!priv->phylink) { @@ -2418,7 +2418,7 @@ static int enetc_phylink_connect(struct net_device *ndev) } /* disable EEE autoneg, until ENETC driver supports it */ - memset(&edata, 0, sizeof(struct ethtool_eee)); + memset(&edata, 0, sizeof(struct ethtool_keee)); phylink_ethtool_set_eee(priv->phylink, &edata); phylink_start(priv->phylink); diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index a8fbcada6b01..a19cb2a786fd 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -672,7 +672,7 @@ struct fec_enet_private { unsigned int itr_clk_rate; /* tx lpi eee mode */ - struct ethtool_eee eee; + struct ethtool_keee eee; unsigned int clk_ref_rate; /* ptp clock period in ns*/ diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 432523b2c789..63707e065141 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3122,7 +3122,7 @@ static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us) static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; unsigned int sleep_cycle, wake_cycle; int ret = 0; @@ -3149,10 +3149,10 @@ static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable) } static int -fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) return -EOPNOTSUPP; @@ -3169,10 +3169,10 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_eee *edata) } static int -fec_enet_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct fec_enet_private *fep = netdev_priv(ndev); - struct ethtool_eee *p = &fep->eee; + struct ethtool_keee *p = &fep->eee; int ret = 0; if (!(fep->quirks & FEC_QUIRK_HAS_EEE)) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index e3dfbd7a4236..a811238c018d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1649,7 +1649,7 @@ static int init_phy(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); phy_interface_t interface = priv->interface; struct phy_device *phydev; - struct ethtool_eee edata; + struct ethtool_keee edata; linkmode_set_bit_array(phy_10_100_features_array, ARRAY_SIZE(phy_10_100_features_array), @@ -1681,7 +1681,7 @@ static int init_phy(struct net_device *dev) phy_support_asym_pause(phydev); /* disable EEE autoneg, EEE not supported by eTSEC */ - memset(&edata, 0, sizeof(struct ethtool_eee)); + memset(&edata, 0, sizeof(struct ethtool_keee)); phy_ethtool_set_eee(phydev, &edata); return 0; diff --git a/drivers/net/ethernet/google/gve/gve.h b/drivers/net/ethernet/google/gve/gve.h index b80349154604..fd290f3ad6ec 100644 --- a/drivers/net/ethernet/google/gve/gve.h +++ b/drivers/net/ethernet/google/gve/gve.h @@ -622,6 +622,55 @@ struct gve_ptype_lut { struct gve_ptype ptypes[GVE_NUM_PTYPES]; }; +/* Parameters for allocating queue page lists */ +struct gve_qpls_alloc_cfg { + struct gve_qpl_config *qpl_cfg; + struct gve_queue_config *tx_cfg; + struct gve_queue_config *rx_cfg; + + u16 num_xdp_queues; + bool raw_addressing; + bool is_gqi; + + /* Allocated resources are returned here */ + struct gve_queue_page_list *qpls; +}; + +/* Parameters for allocating resources for tx queues */ +struct gve_tx_alloc_rings_cfg { + struct gve_queue_config *qcfg; + + /* qpls and qpl_cfg must already be allocated */ + struct gve_queue_page_list *qpls; + struct gve_qpl_config *qpl_cfg; + + u16 ring_size; + u16 start_idx; + u16 num_rings; + bool raw_addressing; + + /* Allocated resources are returned here */ + struct gve_tx_ring *tx; +}; + +/* Parameters for allocating resources for rx queues */ +struct gve_rx_alloc_rings_cfg { + /* tx config is also needed to determine QPL ids */ + struct gve_queue_config *qcfg; + struct gve_queue_config *qcfg_tx; + + /* qpls and qpl_cfg must already be allocated */ + struct gve_queue_page_list *qpls; + struct gve_qpl_config *qpl_cfg; + + u16 ring_size; + bool raw_addressing; + bool enable_header_split; + + /* Allocated resources are returned here */ + struct gve_rx_ring *rx; +}; + /* GVE_QUEUE_FORMAT_UNSPECIFIED must be zero since 0 is the default value * when the entire configure_device_resources command is zeroed out and the * queue_format is not specified. @@ -917,14 +966,14 @@ static inline bool gve_is_qpl(struct gve_priv *priv) priv->queue_format == GVE_DQO_QPL_FORMAT; } -/* Returns the number of tx queue page lists - */ -static inline u32 gve_num_tx_qpls(struct gve_priv *priv) +/* Returns the number of tx queue page lists */ +static inline u32 gve_num_tx_qpls(const struct gve_queue_config *tx_cfg, + int num_xdp_queues, + bool is_qpl) { - if (!gve_is_qpl(priv)) + if (!is_qpl) return 0; - - return priv->tx_cfg.num_queues + priv->num_xdp_queues; + return tx_cfg->num_queues + num_xdp_queues; } /* Returns the number of XDP tx queue page lists @@ -937,14 +986,13 @@ static inline u32 gve_num_xdp_qpls(struct gve_priv *priv) return priv->num_xdp_queues; } -/* Returns the number of rx queue page lists - */ -static inline u32 gve_num_rx_qpls(struct gve_priv *priv) +/* Returns the number of rx queue page lists */ +static inline u32 gve_num_rx_qpls(const struct gve_queue_config *rx_cfg, + bool is_qpl) { - if (!gve_is_qpl(priv)) + if (!is_qpl) return 0; - - return priv->rx_cfg.num_queues; + return rx_cfg->num_queues; } static inline u32 gve_tx_qpl_id(struct gve_priv *priv, int tx_qid) @@ -957,59 +1005,59 @@ static inline u32 gve_rx_qpl_id(struct gve_priv *priv, int rx_qid) return priv->tx_cfg.max_queues + rx_qid; } +/* Returns the index into priv->qpls where a certain rx queue's QPL resides */ +static inline u32 gve_get_rx_qpl_id(const struct gve_queue_config *tx_cfg, int rx_qid) +{ + return tx_cfg->max_queues + rx_qid; +} + static inline u32 gve_tx_start_qpl_id(struct gve_priv *priv) { return gve_tx_qpl_id(priv, 0); } -static inline u32 gve_rx_start_qpl_id(struct gve_priv *priv) +/* Returns the index into priv->qpls where the first rx queue's QPL resides */ +static inline u32 gve_rx_start_qpl_id(const struct gve_queue_config *tx_cfg) { - return gve_rx_qpl_id(priv, 0); + return gve_get_rx_qpl_id(tx_cfg, 0); } -/* Returns a pointer to the next available tx qpl in the list of qpls - */ +/* Returns a pointer to the next available tx qpl in the list of qpls */ static inline -struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_priv *priv, int tx_qid) +struct gve_queue_page_list *gve_assign_tx_qpl(struct gve_tx_alloc_rings_cfg *cfg, + int tx_qid) { - int id = gve_tx_qpl_id(priv, tx_qid); - /* QPL already in use */ - if (test_bit(id, priv->qpl_cfg.qpl_id_map)) + if (test_bit(tx_qid, cfg->qpl_cfg->qpl_id_map)) return NULL; - - set_bit(id, priv->qpl_cfg.qpl_id_map); - return &priv->qpls[id]; + set_bit(tx_qid, cfg->qpl_cfg->qpl_id_map); + return &cfg->qpls[tx_qid]; } -/* Returns a pointer to the next available rx qpl in the list of qpls - */ +/* Returns a pointer to the next available rx qpl in the list of qpls */ static inline -struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_priv *priv, int rx_qid) +struct gve_queue_page_list *gve_assign_rx_qpl(struct gve_rx_alloc_rings_cfg *cfg, + int rx_qid) { - int id = gve_rx_qpl_id(priv, rx_qid); - + int id = gve_get_rx_qpl_id(cfg->qcfg_tx, rx_qid); /* QPL already in use */ - if (test_bit(id, priv->qpl_cfg.qpl_id_map)) + if (test_bit(id, cfg->qpl_cfg->qpl_id_map)) return NULL; - - set_bit(id, priv->qpl_cfg.qpl_id_map); - return &priv->qpls[id]; + set_bit(id, cfg->qpl_cfg->qpl_id_map); + return &cfg->qpls[id]; } -/* Unassigns the qpl with the given id - */ -static inline void gve_unassign_qpl(struct gve_priv *priv, int id) +/* Unassigns the qpl with the given id */ +static inline void gve_unassign_qpl(struct gve_qpl_config *qpl_cfg, int id) { - clear_bit(id, priv->qpl_cfg.qpl_id_map); + clear_bit(id, qpl_cfg->qpl_id_map); } -/* Returns the correct dma direction for tx and rx qpls - */ +/* Returns the correct dma direction for tx and rx qpls */ static inline enum dma_data_direction gve_qpl_dma_dir(struct gve_priv *priv, int id) { - if (id < gve_rx_start_qpl_id(priv)) + if (id < gve_rx_start_qpl_id(&priv->tx_cfg)) return DMA_TO_DEVICE; else return DMA_FROM_DEVICE; @@ -1036,6 +1084,9 @@ static inline u32 gve_xdp_tx_start_queue_id(struct gve_priv *priv) return gve_xdp_tx_queue_id(priv, 0); } +/* gqi napi handler defined in gve_main.c */ +int gve_napi_poll(struct napi_struct *napi, int budget); + /* buffers */ int gve_alloc_page(struct gve_priv *priv, struct device *dev, struct page **page, dma_addr_t *dma, @@ -1051,8 +1102,12 @@ int gve_xdp_xmit_one(struct gve_priv *priv, struct gve_tx_ring *tx, void gve_xdp_tx_flush(struct gve_priv *priv, u32 xdp_qid); bool gve_tx_poll(struct gve_notify_block *block, int budget); bool gve_xdp_poll(struct gve_notify_block *block, int budget); -int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings); -void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings); +int gve_tx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_free_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx); +void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx); u32 gve_tx_load_event_counter(struct gve_priv *priv, struct gve_tx_ring *tx); bool gve_tx_clean_pending(struct gve_priv *priv, struct gve_tx_ring *tx); @@ -1061,7 +1116,12 @@ void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx); int gve_rx_poll(struct gve_notify_block *block, int budget); bool gve_rx_work_pending(struct gve_rx_ring *rx); int gve_rx_alloc_rings(struct gve_priv *priv); -void gve_rx_free_rings_gqi(struct gve_priv *priv); +int gve_rx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_free_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx); +void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx); /* Reset */ void gve_schedule_reset(struct gve_priv *priv); int gve_reset(struct gve_priv *priv, bool attempt_teardown); diff --git a/drivers/net/ethernet/google/gve/gve_dqo.h b/drivers/net/ethernet/google/gve/gve_dqo.h index c36b93f0de15..b81584829c40 100644 --- a/drivers/net/ethernet/google/gve/gve_dqo.h +++ b/drivers/net/ethernet/google/gve/gve_dqo.h @@ -38,10 +38,18 @@ netdev_features_t gve_features_check_dqo(struct sk_buff *skb, netdev_features_t features); bool gve_tx_poll_dqo(struct gve_notify_block *block, bool do_clean); int gve_rx_poll_dqo(struct gve_notify_block *block, int budget); -int gve_tx_alloc_rings_dqo(struct gve_priv *priv); -void gve_tx_free_rings_dqo(struct gve_priv *priv); -int gve_rx_alloc_rings_dqo(struct gve_priv *priv); -void gve_rx_free_rings_dqo(struct gve_priv *priv); +int gve_tx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_free_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg); +void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx); +void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx); +int gve_rx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_free_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg); +void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx); +void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx); int gve_clean_tx_done_dqo(struct gve_priv *priv, struct gve_tx_ring *tx, struct napi_struct *napi); void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx); @@ -93,4 +101,6 @@ gve_set_itr_coalesce_usecs_dqo(struct gve_priv *priv, gve_write_irq_doorbell_dqo(priv, block, gve_setup_itr_interval_dqo(usecs)); } + +int gve_napi_poll_dqo(struct napi_struct *napi, int budget); #endif /* _GVE_DQO_H_ */ diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index 619bf63ec935..db6d9ae7cd78 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -22,6 +22,7 @@ #include "gve_dqo.h" #include "gve_adminq.h" #include "gve_register.h" +#include "gve_utils.h" #define GVE_DEFAULT_RX_COPYBREAK (256) @@ -252,7 +253,7 @@ static irqreturn_t gve_intr_dqo(int irq, void *arg) return IRQ_HANDLED; } -static int gve_napi_poll(struct napi_struct *napi, int budget) +int gve_napi_poll(struct napi_struct *napi, int budget) { struct gve_notify_block *block; __be32 __iomem *irq_doorbell; @@ -302,7 +303,7 @@ static int gve_napi_poll(struct napi_struct *napi, int budget) return work_done; } -static int gve_napi_poll_dqo(struct napi_struct *napi, int budget) +int gve_napi_poll_dqo(struct napi_struct *napi, int budget) { struct gve_notify_block *block = container_of(napi, struct gve_notify_block, napi); @@ -581,19 +582,59 @@ static void gve_teardown_device_resources(struct gve_priv *priv) gve_clear_device_resources_ok(priv); } -static void gve_add_napi(struct gve_priv *priv, int ntfy_idx, - int (*gve_poll)(struct napi_struct *, int)) +static int gve_unregister_qpl(struct gve_priv *priv, u32 i) { - struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + int err; + + err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); + if (err) { + netif_err(priv, drv, priv->dev, + "Failed to unregister queue page list %d\n", + priv->qpls[i].id); + return err; + } - netif_napi_add(priv->dev, &block->napi, gve_poll); + priv->num_registered_pages -= priv->qpls[i].num_entries; + return 0; } -static void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) +static int gve_register_qpl(struct gve_priv *priv, u32 i) { - struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + int num_rx_qpls; + int pages; + int err; + + /* Rx QPLs succeed Tx QPLs in the priv->qpls array. */ + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + if (i >= gve_rx_start_qpl_id(&priv->tx_cfg) + num_rx_qpls) { + netif_err(priv, drv, priv->dev, + "Cannot register nonexisting QPL at index %d\n", i); + return -EINVAL; + } + + pages = priv->qpls[i].num_entries; + + if (pages + priv->num_registered_pages > priv->max_registered_pages) { + netif_err(priv, drv, priv->dev, + "Reached max number of registered pages %llu > %llu\n", + pages + priv->num_registered_pages, + priv->max_registered_pages); + return -EINVAL; + } - netif_napi_del(&block->napi); + err = gve_adminq_register_page_list(priv, &priv->qpls[i]); + if (err) { + netif_err(priv, drv, priv->dev, + "failed to register queue page list %d\n", + priv->qpls[i].id); + /* This failure will trigger a reset - no need to clean + * up + */ + return err; + } + + priv->num_registered_pages += pages; + return 0; } static int gve_register_xdp_qpls(struct gve_priv *priv) @@ -602,55 +643,41 @@ static int gve_register_xdp_qpls(struct gve_priv *priv) int err; int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); + start_id = gve_xdp_tx_start_queue_id(priv); for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + err = gve_register_qpl(priv, i); + /* This failure will trigger a reset - no need to clean up */ + if (err) return err; - } } return 0; } static int gve_register_qpls(struct gve_priv *priv) { + int num_tx_qpls, num_rx_qpls; int start_id; int err; int i; - start_id = gve_tx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv), + gve_is_qpl(priv)); + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + + for (i = 0; i < num_tx_qpls; i++) { + err = gve_register_qpl(priv, i); + if (err) return err; - } } - start_id = gve_rx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_adminq_register_page_list(priv, &priv->qpls[i]); - if (err) { - netif_err(priv, drv, priv->dev, - "failed to register queue page list %d\n", - priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean - * up - */ + /* there might be a gap between the tx and rx qpl ids */ + start_id = gve_rx_start_qpl_id(&priv->tx_cfg); + for (i = 0; i < num_rx_qpls; i++) { + err = gve_register_qpl(priv, start_id + i); + if (err) return err; - } } + return 0; } @@ -660,48 +687,40 @@ static int gve_unregister_xdp_qpls(struct gve_priv *priv) int err; int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); + start_id = gve_xdp_tx_start_queue_id(priv); for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + err = gve_unregister_qpl(priv, i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } return 0; } static int gve_unregister_qpls(struct gve_priv *priv) { + int num_tx_qpls, num_rx_qpls; int start_id; int err; int i; - start_id = gve_tx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + num_tx_qpls = gve_num_tx_qpls(&priv->tx_cfg, gve_num_xdp_qpls(priv), + gve_is_qpl(priv)); + num_rx_qpls = gve_num_rx_qpls(&priv->rx_cfg, gve_is_qpl(priv)); + + for (i = 0; i < num_tx_qpls; i++) { + err = gve_unregister_qpl(priv, i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } - start_id = gve_rx_start_qpl_id(priv); - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id); - /* This failure will trigger a reset - no need to clean up */ - if (err) { - netif_err(priv, drv, priv->dev, - "Failed to unregister queue page list %d\n", - priv->qpls[i].id); + start_id = gve_rx_start_qpl_id(&priv->tx_cfg); + for (i = 0; i < num_rx_qpls; i++) { + err = gve_unregister_qpl(priv, start_id + i); + /* This failure will trigger a reset - no need to clean */ + if (err) return err; - } } return 0; } @@ -776,120 +795,124 @@ static int gve_create_rings(struct gve_priv *priv) return 0; } -static void add_napi_init_xdp_sync_stats(struct gve_priv *priv, - int (*napi_poll)(struct napi_struct *napi, - int budget)) +static void init_xdp_sync_stats(struct gve_priv *priv) { int start_id = gve_xdp_tx_start_queue_id(priv); int i; - /* Add xdp tx napi & init sync stats*/ + /* Init stats */ for (i = start_id; i < start_id + priv->num_xdp_queues; i++) { int ntfy_idx = gve_tx_idx_to_ntfy(priv, i); u64_stats_init(&priv->tx[i].statss); priv->tx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); } } -static void add_napi_init_sync_stats(struct gve_priv *priv, - int (*napi_poll)(struct napi_struct *napi, - int budget)) +static void gve_init_sync_stats(struct gve_priv *priv) { int i; - /* Add tx napi & init sync stats*/ - for (i = 0; i < gve_num_tx_queues(priv); i++) { - int ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - + for (i = 0; i < priv->tx_cfg.num_queues; i++) u64_stats_init(&priv->tx[i].statss); - priv->tx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); - } - /* Add rx napi & init sync stats*/ - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - int ntfy_idx = gve_rx_idx_to_ntfy(priv, i); + /* Init stats for XDP TX queues */ + init_xdp_sync_stats(priv); + + for (i = 0; i < priv->rx_cfg.num_queues; i++) u64_stats_init(&priv->rx[i].statss); - priv->rx[i].ntfy_id = ntfy_idx; - gve_add_napi(priv, ntfy_idx, napi_poll); +} + +static void gve_tx_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) +{ + cfg->qcfg = &priv->tx_cfg; + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->qpls = priv->qpls; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->ring_size = priv->tx_desc_cnt; + cfg->start_idx = 0; + cfg->num_rings = gve_num_tx_queues(priv); + cfg->tx = priv->tx; +} + +static void gve_tx_stop_rings(struct gve_priv *priv, int start_id, int num_rings) +{ + int i; + + if (!priv->tx) + return; + + for (i = start_id; i < start_id + num_rings; i++) { + if (gve_is_gqi(priv)) + gve_tx_stop_ring_gqi(priv, i); + else + gve_tx_stop_ring_dqo(priv, i); } } -static void gve_tx_free_rings(struct gve_priv *priv, int start_id, int num_rings) +static void gve_tx_start_rings(struct gve_priv *priv, int start_id, + int num_rings) { - if (gve_is_gqi(priv)) { - gve_tx_free_rings_gqi(priv, start_id, num_rings); - } else { - gve_tx_free_rings_dqo(priv); + int i; + + for (i = start_id; i < start_id + num_rings; i++) { + if (gve_is_gqi(priv)) + gve_tx_start_ring_gqi(priv, i); + else + gve_tx_start_ring_dqo(priv, i); } } static int gve_alloc_xdp_rings(struct gve_priv *priv) { - int start_id; + struct gve_tx_alloc_rings_cfg cfg = {0}; int err = 0; if (!priv->num_xdp_queues) return 0; - start_id = gve_xdp_tx_start_queue_id(priv); - err = gve_tx_alloc_rings(priv, start_id, priv->num_xdp_queues); + gve_tx_get_curr_alloc_cfg(priv, &cfg); + cfg.start_idx = gve_xdp_tx_start_queue_id(priv); + cfg.num_rings = priv->num_xdp_queues; + + err = gve_tx_alloc_rings_gqi(priv, &cfg); if (err) return err; - add_napi_init_xdp_sync_stats(priv, gve_napi_poll); + + gve_tx_start_rings(priv, cfg.start_idx, cfg.num_rings); + init_xdp_sync_stats(priv); return 0; } -static int gve_alloc_rings(struct gve_priv *priv) +static int gve_alloc_rings(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) { int err; - /* Setup tx rings */ - priv->tx = kvcalloc(priv->tx_cfg.max_queues, sizeof(*priv->tx), - GFP_KERNEL); - if (!priv->tx) - return -ENOMEM; - if (gve_is_gqi(priv)) - err = gve_tx_alloc_rings(priv, 0, gve_num_tx_queues(priv)); + err = gve_tx_alloc_rings_gqi(priv, tx_alloc_cfg); else - err = gve_tx_alloc_rings_dqo(priv); + err = gve_tx_alloc_rings_dqo(priv, tx_alloc_cfg); if (err) - goto free_tx; - - /* Setup rx rings */ - priv->rx = kvcalloc(priv->rx_cfg.max_queues, sizeof(*priv->rx), - GFP_KERNEL); - if (!priv->rx) { - err = -ENOMEM; - goto free_tx_queue; - } + return err; if (gve_is_gqi(priv)) - err = gve_rx_alloc_rings(priv); + err = gve_rx_alloc_rings_gqi(priv, rx_alloc_cfg); else - err = gve_rx_alloc_rings_dqo(priv); + err = gve_rx_alloc_rings_dqo(priv, rx_alloc_cfg); if (err) - goto free_rx; - - if (gve_is_gqi(priv)) - add_napi_init_sync_stats(priv, gve_napi_poll); - else - add_napi_init_sync_stats(priv, gve_napi_poll_dqo); + goto free_tx; return 0; -free_rx: - kvfree(priv->rx); - priv->rx = NULL; -free_tx_queue: - gve_tx_free_rings(priv, 0, gve_num_tx_queues(priv)); free_tx: - kvfree(priv->tx); - priv->tx = NULL; + if (gve_is_gqi(priv)) + gve_tx_free_rings_gqi(priv, tx_alloc_cfg); + else + gve_tx_free_rings_dqo(priv, tx_alloc_cfg); return err; } @@ -937,52 +960,30 @@ static int gve_destroy_rings(struct gve_priv *priv) return 0; } -static void gve_rx_free_rings(struct gve_priv *priv) -{ - if (gve_is_gqi(priv)) - gve_rx_free_rings_gqi(priv); - else - gve_rx_free_rings_dqo(priv); -} - static void gve_free_xdp_rings(struct gve_priv *priv) { - int ntfy_idx, start_id; - int i; + struct gve_tx_alloc_rings_cfg cfg = {0}; + + gve_tx_get_curr_alloc_cfg(priv, &cfg); + cfg.start_idx = gve_xdp_tx_start_queue_id(priv); + cfg.num_rings = priv->num_xdp_queues; - start_id = gve_xdp_tx_start_queue_id(priv); if (priv->tx) { - for (i = start_id; i < start_id + priv->num_xdp_queues; i++) { - ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_tx_free_rings(priv, start_id, priv->num_xdp_queues); + gve_tx_stop_rings(priv, cfg.start_idx, cfg.num_rings); + gve_tx_free_rings_gqi(priv, &cfg); } } -static void gve_free_rings(struct gve_priv *priv) +static void gve_free_rings(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *tx_cfg, + struct gve_rx_alloc_rings_cfg *rx_cfg) { - int num_tx_queues = gve_num_tx_queues(priv); - int ntfy_idx; - int i; - - if (priv->tx) { - for (i = 0; i < num_tx_queues; i++) { - ntfy_idx = gve_tx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_tx_free_rings(priv, 0, num_tx_queues); - kvfree(priv->tx); - priv->tx = NULL; - } - if (priv->rx) { - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - ntfy_idx = gve_rx_idx_to_ntfy(priv, i); - gve_remove_napi(priv, ntfy_idx); - } - gve_rx_free_rings(priv); - kvfree(priv->rx); - priv->rx = NULL; + if (gve_is_gqi(priv)) { + gve_tx_free_rings_gqi(priv, tx_cfg); + gve_rx_free_rings_gqi(priv, rx_cfg); + } else { + gve_tx_free_rings_dqo(priv, tx_cfg); + gve_rx_free_rings_dqo(priv, rx_cfg); } } @@ -1004,21 +1005,13 @@ int gve_alloc_page(struct gve_priv *priv, struct device *dev, return 0; } -static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, - int pages) +static int gve_alloc_queue_page_list(struct gve_priv *priv, + struct gve_queue_page_list *qpl, + u32 id, int pages) { - struct gve_queue_page_list *qpl = &priv->qpls[id]; int err; int i; - if (pages + priv->num_registered_pages > priv->max_registered_pages) { - netif_err(priv, drv, priv->dev, - "Reached max number of registered pages %llu > %llu\n", - pages + priv->num_registered_pages, - priv->max_registered_pages); - return -EINVAL; - } - qpl->id = id; qpl->num_entries = 0; qpl->pages = kvcalloc(pages, sizeof(*qpl->pages), GFP_KERNEL); @@ -1039,7 +1032,6 @@ static int gve_alloc_queue_page_list(struct gve_priv *priv, u32 id, return -ENOMEM; qpl->num_entries++; } - priv->num_registered_pages += pages; return 0; } @@ -1053,9 +1045,10 @@ void gve_free_page(struct device *dev, struct page *page, dma_addr_t dma, put_page(page); } -static void gve_free_queue_page_list(struct gve_priv *priv, u32 id) +static void gve_free_queue_page_list(struct gve_priv *priv, + struct gve_queue_page_list *qpl, + int id) { - struct gve_queue_page_list *qpl = &priv->qpls[id]; int i; if (!qpl->pages) @@ -1072,19 +1065,30 @@ static void gve_free_queue_page_list(struct gve_priv *priv, u32 id) free_pages: kvfree(qpl->pages); qpl->pages = NULL; - priv->num_registered_pages -= qpl->num_entries; } -static int gve_alloc_xdp_qpls(struct gve_priv *priv) +static void gve_free_n_qpls(struct gve_priv *priv, + struct gve_queue_page_list *qpls, + int start_id, + int num_qpls) +{ + int i; + + for (i = start_id; i < start_id + num_qpls; i++) + gve_free_queue_page_list(priv, &qpls[i], i); +} + +static int gve_alloc_n_qpls(struct gve_priv *priv, + struct gve_queue_page_list *qpls, + int page_count, + int start_id, + int num_qpls) { - int start_id; - int i, j; int err; + int i; - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); - for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - priv->tx_pages_per_qpl); + for (i = start_id; i < start_id + num_qpls; i++) { + err = gve_alloc_queue_page_list(priv, &qpls[i], i, page_count); if (err) goto free_qpls; } @@ -1092,95 +1096,89 @@ static int gve_alloc_xdp_qpls(struct gve_priv *priv) return 0; free_qpls: - for (j = start_id; j <= i; j++) - gve_free_queue_page_list(priv, j); + /* Must include the failing QPL too for gve_alloc_queue_page_list fails + * without cleaning up. + */ + gve_free_n_qpls(priv, qpls, start_id, i - start_id + 1); return err; } -static int gve_alloc_qpls(struct gve_priv *priv) +static int gve_alloc_qpls(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) { - int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues; + int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues; + int rx_start_id, tx_num_qpls, rx_num_qpls; + struct gve_queue_page_list *qpls; int page_count; - int start_id; - int i, j; int err; - if (!gve_is_qpl(priv)) + if (cfg->raw_addressing) return 0; - priv->qpls = kvcalloc(max_queues, sizeof(*priv->qpls), GFP_KERNEL); - if (!priv->qpls) + qpls = kvcalloc(max_queues, sizeof(*qpls), GFP_KERNEL); + if (!qpls) return -ENOMEM; - start_id = gve_tx_start_qpl_id(priv); - page_count = priv->tx_pages_per_qpl; - for (i = start_id; i < start_id + gve_num_tx_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - page_count); - if (err) - goto free_qpls; + cfg->qpl_cfg->qpl_map_size = BITS_TO_LONGS(max_queues) * + sizeof(unsigned long) * BITS_PER_BYTE; + cfg->qpl_cfg->qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues), + sizeof(unsigned long), GFP_KERNEL); + if (!cfg->qpl_cfg->qpl_id_map) { + err = -ENOMEM; + goto free_qpl_array; } - start_id = gve_rx_start_qpl_id(priv); + /* Allocate TX QPLs */ + page_count = priv->tx_pages_per_qpl; + tx_num_qpls = gve_num_tx_qpls(cfg->tx_cfg, cfg->num_xdp_queues, + gve_is_qpl(priv)); + err = gve_alloc_n_qpls(priv, qpls, page_count, 0, tx_num_qpls); + if (err) + goto free_qpl_map; + /* Allocate RX QPLs */ + rx_start_id = gve_rx_start_qpl_id(cfg->tx_cfg); /* For GQI_QPL number of pages allocated have 1:1 relationship with * number of descriptors. For DQO, number of pages required are * more than descriptors (because of out of order completions). */ - page_count = priv->queue_format == GVE_GQI_QPL_FORMAT ? - priv->rx_data_slot_cnt : priv->rx_pages_per_qpl; - for (i = start_id; i < start_id + gve_num_rx_qpls(priv); i++) { - err = gve_alloc_queue_page_list(priv, i, - page_count); - if (err) - goto free_qpls; - } - - priv->qpl_cfg.qpl_map_size = BITS_TO_LONGS(max_queues) * - sizeof(unsigned long) * BITS_PER_BYTE; - priv->qpl_cfg.qpl_id_map = kvcalloc(BITS_TO_LONGS(max_queues), - sizeof(unsigned long), GFP_KERNEL); - if (!priv->qpl_cfg.qpl_id_map) { - err = -ENOMEM; - goto free_qpls; - } + page_count = cfg->is_gqi ? priv->rx_data_slot_cnt : priv->rx_pages_per_qpl; + rx_num_qpls = gve_num_rx_qpls(cfg->rx_cfg, gve_is_qpl(priv)); + err = gve_alloc_n_qpls(priv, qpls, page_count, rx_start_id, rx_num_qpls); + if (err) + goto free_tx_qpls; + cfg->qpls = qpls; return 0; -free_qpls: - for (j = 0; j <= i; j++) - gve_free_queue_page_list(priv, j); - kvfree(priv->qpls); - priv->qpls = NULL; +free_tx_qpls: + gve_free_n_qpls(priv, qpls, 0, tx_num_qpls); +free_qpl_map: + kvfree(cfg->qpl_cfg->qpl_id_map); + cfg->qpl_cfg->qpl_id_map = NULL; +free_qpl_array: + kvfree(qpls); return err; } -static void gve_free_xdp_qpls(struct gve_priv *priv) -{ - int start_id; - int i; - - start_id = gve_tx_qpl_id(priv, gve_xdp_tx_start_queue_id(priv)); - for (i = start_id; i < start_id + gve_num_xdp_qpls(priv); i++) - gve_free_queue_page_list(priv, i); -} - -static void gve_free_qpls(struct gve_priv *priv) +static void gve_free_qpls(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) { - int max_queues = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues; + int max_queues = cfg->tx_cfg->max_queues + cfg->rx_cfg->max_queues; + struct gve_queue_page_list *qpls = cfg->qpls; int i; - if (!priv->qpls) + if (!qpls) return; - kvfree(priv->qpl_cfg.qpl_id_map); - priv->qpl_cfg.qpl_id_map = NULL; + kvfree(cfg->qpl_cfg->qpl_id_map); + cfg->qpl_cfg->qpl_id_map = NULL; for (i = 0; i < max_queues; i++) - gve_free_queue_page_list(priv, i); + gve_free_queue_page_list(priv, &qpls[i], i); - kvfree(priv->qpls); - priv->qpls = NULL; + kvfree(qpls); + cfg->qpls = NULL; } /* Use this to schedule a reset when the device is capable of continuing @@ -1291,34 +1289,160 @@ static void gve_drain_page_cache(struct gve_priv *priv) } } -static int gve_open(struct net_device *dev) +static void gve_qpls_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *cfg) +{ + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->is_gqi = gve_is_gqi(priv); + cfg->num_xdp_queues = priv->num_xdp_queues; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->tx_cfg = &priv->tx_cfg; + cfg->rx_cfg = &priv->rx_cfg; + cfg->qpls = priv->qpls; +} + +static void gve_rx_get_curr_alloc_cfg(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) +{ + cfg->qcfg = &priv->rx_cfg; + cfg->qcfg_tx = &priv->tx_cfg; + cfg->raw_addressing = !gve_is_qpl(priv); + cfg->qpls = priv->qpls; + cfg->qpl_cfg = &priv->qpl_cfg; + cfg->ring_size = priv->rx_desc_cnt; + cfg->rx = priv->rx; +} + +static void gve_get_curr_alloc_cfgs(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + gve_qpls_get_curr_alloc_cfg(priv, qpls_alloc_cfg); + gve_tx_get_curr_alloc_cfg(priv, tx_alloc_cfg); + gve_rx_get_curr_alloc_cfg(priv, rx_alloc_cfg); +} + +static void gve_rx_start_rings(struct gve_priv *priv, int num_rings) +{ + int i; + + for (i = 0; i < num_rings; i++) { + if (gve_is_gqi(priv)) + gve_rx_start_ring_gqi(priv, i); + else + gve_rx_start_ring_dqo(priv, i); + } +} + +static void gve_rx_stop_rings(struct gve_priv *priv, int num_rings) +{ + int i; + + if (!priv->rx) + return; + + for (i = 0; i < num_rings; i++) { + if (gve_is_gqi(priv)) + gve_rx_stop_ring_gqi(priv, i); + else + gve_rx_stop_ring_dqo(priv, i); + } +} + +static void gve_queues_mem_free(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + gve_free_rings(priv, tx_alloc_cfg, rx_alloc_cfg); + gve_free_qpls(priv, qpls_alloc_cfg); +} + +static int gve_queues_mem_alloc(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) { - struct gve_priv *priv = netdev_priv(dev); int err; + err = gve_alloc_qpls(priv, qpls_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, "Failed to alloc QPLs\n"); + return err; + } + tx_alloc_cfg->qpls = qpls_alloc_cfg->qpls; + rx_alloc_cfg->qpls = qpls_alloc_cfg->qpls; + err = gve_alloc_rings(priv, tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, "Failed to alloc rings\n"); + goto free_qpls; + } + + return 0; + +free_qpls: + gve_free_qpls(priv, qpls_alloc_cfg); + return err; +} + +static void gve_queues_mem_remove(struct gve_priv *priv) +{ + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; + + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + gve_queues_mem_free(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + priv->qpls = NULL; + priv->tx = NULL; + priv->rx = NULL; +} + +/* The passed-in queue memory is stored into priv and the queues are made live. + * No memory is allocated. Passed-in memory is freed on errors. + */ +static int gve_queues_start(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + struct net_device *dev = priv->dev; + int err; + + /* Record new resources into priv */ + priv->qpls = qpls_alloc_cfg->qpls; + priv->tx = tx_alloc_cfg->tx; + priv->rx = rx_alloc_cfg->rx; + + /* Record new configs into priv */ + priv->qpl_cfg = *qpls_alloc_cfg->qpl_cfg; + priv->tx_cfg = *tx_alloc_cfg->qcfg; + priv->rx_cfg = *rx_alloc_cfg->qcfg; + priv->tx_desc_cnt = tx_alloc_cfg->ring_size; + priv->rx_desc_cnt = rx_alloc_cfg->ring_size; + if (priv->xdp_prog) priv->num_xdp_queues = priv->rx_cfg.num_queues; else priv->num_xdp_queues = 0; - err = gve_alloc_qpls(priv); - if (err) - return err; - - err = gve_alloc_rings(priv); - if (err) - goto free_qpls; + gve_tx_start_rings(priv, 0, tx_alloc_cfg->num_rings); + gve_rx_start_rings(priv, rx_alloc_cfg->qcfg->num_queues); + gve_init_sync_stats(priv); err = netif_set_real_num_tx_queues(dev, priv->tx_cfg.num_queues); if (err) - goto free_rings; + goto stop_and_free_rings; err = netif_set_real_num_rx_queues(dev, priv->rx_cfg.num_queues); if (err) - goto free_rings; + goto stop_and_free_rings; err = gve_reg_xdp_info(priv, dev); if (err) - goto free_rings; + goto stop_and_free_rings; err = gve_register_qpls(priv); if (err) @@ -1346,32 +1470,53 @@ static int gve_open(struct net_device *dev) priv->interface_up_cnt++; return 0; -free_rings: - gve_free_rings(priv); -free_qpls: - gve_free_qpls(priv); - return err; - reset: - /* This must have been called from a reset due to the rtnl lock - * so just return at this point. - */ if (gve_get_reset_in_progress(priv)) - return err; - /* Otherwise reset before returning */ + goto stop_and_free_rings; gve_reset_and_teardown(priv, true); /* if this fails there is nothing we can do so just ignore the return */ gve_reset_recovery(priv, false); /* return the original error */ return err; +stop_and_free_rings: + gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv)); + gve_rx_stop_rings(priv, priv->rx_cfg.num_queues); + gve_queues_mem_remove(priv); + return err; } -static int gve_close(struct net_device *dev) +static int gve_open(struct net_device *dev) { + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; struct gve_priv *priv = netdev_priv(dev); int err; - netif_carrier_off(dev); + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + + err = gve_queues_mem_alloc(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) + return err; + + /* No need to free on error: ownership of resources is lost after + * calling gve_queues_start. + */ + err = gve_queues_start(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) + return err; + + return 0; +} + +static int gve_queues_stop(struct gve_priv *priv) +{ + int err; + + netif_carrier_off(priv->dev); if (gve_get_device_rings_ok(priv)) { gve_turndown(priv); gve_drain_page_cache(priv); @@ -1386,8 +1531,10 @@ static int gve_close(struct net_device *dev) del_timer_sync(&priv->stats_report_timer); gve_unreg_xdp_info(priv); - gve_free_rings(priv); - gve_free_qpls(priv); + + gve_tx_stop_rings(priv, 0, gve_num_tx_queues(priv)); + gve_rx_stop_rings(priv, priv->rx_cfg.num_queues); + priv->interface_down_cnt++; return 0; @@ -1402,10 +1549,26 @@ err: return gve_reset_recovery(priv, false); } +static int gve_close(struct net_device *dev) +{ + struct gve_priv *priv = netdev_priv(dev); + int err; + + err = gve_queues_stop(priv); + if (err) + return err; + + gve_queues_mem_remove(priv); + return 0; +} + static int gve_remove_xdp_queues(struct gve_priv *priv) { + int qpl_start_id; int err; + qpl_start_id = gve_xdp_tx_start_queue_id(priv); + err = gve_destroy_xdp_rings(priv); if (err) return err; @@ -1416,18 +1579,22 @@ static int gve_remove_xdp_queues(struct gve_priv *priv) gve_unreg_xdp_info(priv); gve_free_xdp_rings(priv); - gve_free_xdp_qpls(priv); + + gve_free_n_qpls(priv, priv->qpls, qpl_start_id, gve_num_xdp_qpls(priv)); priv->num_xdp_queues = 0; return 0; } static int gve_add_xdp_queues(struct gve_priv *priv) { + int start_id; int err; - priv->num_xdp_queues = priv->tx_cfg.num_queues; + priv->num_xdp_queues = priv->rx_cfg.num_queues; - err = gve_alloc_xdp_qpls(priv); + start_id = gve_xdp_tx_start_queue_id(priv); + err = gve_alloc_n_qpls(priv, priv->qpls, priv->tx_pages_per_qpl, + start_id, gve_num_xdp_qpls(priv)); if (err) goto err; @@ -1452,7 +1619,7 @@ static int gve_add_xdp_queues(struct gve_priv *priv) free_xdp_rings: gve_free_xdp_rings(priv); free_xdp_qpls: - gve_free_xdp_qpls(priv); + gve_free_n_qpls(priv, priv->qpls, start_id, gve_num_xdp_qpls(priv)); err: priv->num_xdp_queues = 0; return err; @@ -1702,42 +1869,87 @@ static int gve_xdp(struct net_device *dev, struct netdev_bpf *xdp) } } +static int gve_adjust_config(struct gve_priv *priv, + struct gve_qpls_alloc_cfg *qpls_alloc_cfg, + struct gve_tx_alloc_rings_cfg *tx_alloc_cfg, + struct gve_rx_alloc_rings_cfg *rx_alloc_cfg) +{ + int err; + + /* Allocate resources for the new confiugration */ + err = gve_queues_mem_alloc(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to alloc new queues"); + return err; + } + + /* Teardown the device and free existing resources */ + err = gve_close(priv->dev); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to close old queues"); + gve_queues_mem_free(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + return err; + } + + /* Bring the device back up again with the new resources. */ + err = gve_queues_start(priv, qpls_alloc_cfg, + tx_alloc_cfg, rx_alloc_cfg); + if (err) { + netif_err(priv, drv, priv->dev, + "Adjust config failed to start new queues, !!! DISABLING ALL QUEUES !!!\n"); + /* No need to free on error: ownership of resources is lost after + * calling gve_queues_start. + */ + gve_turndown(priv); + return err; + } + + return 0; +} + int gve_adjust_queues(struct gve_priv *priv, struct gve_queue_config new_rx_config, struct gve_queue_config new_tx_config) { + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; + struct gve_qpl_config new_qpl_cfg; int err; - if (netif_carrier_ok(priv->dev)) { - /* To make this process as simple as possible we teardown the - * device, set the new configuration, and then bring the device - * up again. - */ - err = gve_close(priv->dev); - /* we have already tried to reset in close, - * just fail at this point - */ - if (err) - return err; - priv->tx_cfg = new_tx_config; - priv->rx_cfg = new_rx_config; + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); - err = gve_open(priv->dev); - if (err) - goto err; + /* qpl_cfg is not read-only, it contains a map that gets updated as + * rings are allocated, which is why we cannot use the yet unreleased + * one in priv. + */ + qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg; + tx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + rx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + + /* Relay the new config from ethtool */ + qpls_alloc_cfg.tx_cfg = &new_tx_config; + tx_alloc_cfg.qcfg = &new_tx_config; + rx_alloc_cfg.qcfg_tx = &new_tx_config; + qpls_alloc_cfg.rx_cfg = &new_rx_config; + rx_alloc_cfg.qcfg = &new_rx_config; + tx_alloc_cfg.num_rings = new_tx_config.num_queues; - return 0; + if (netif_carrier_ok(priv->dev)) { + err = gve_adjust_config(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + return err; } /* Set the config for the next up. */ priv->tx_cfg = new_tx_config; priv->rx_cfg = new_rx_config; return 0; -err: - netif_err(priv, drv, priv->dev, - "Adjust queues failed! !!! DISABLING ALL QUEUES !!!\n"); - gve_turndown(priv); - return err; } static void gve_turndown(struct gve_priv *priv) @@ -1857,36 +2069,37 @@ static int gve_set_features(struct net_device *netdev, netdev_features_t features) { const netdev_features_t orig_features = netdev->features; + struct gve_tx_alloc_rings_cfg tx_alloc_cfg = {0}; + struct gve_rx_alloc_rings_cfg rx_alloc_cfg = {0}; + struct gve_qpls_alloc_cfg qpls_alloc_cfg = {0}; struct gve_priv *priv = netdev_priv(netdev); + struct gve_qpl_config new_qpl_cfg; int err; + gve_get_curr_alloc_cfgs(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + /* qpl_cfg is not read-only, it contains a map that gets updated as + * rings are allocated, which is why we cannot use the yet unreleased + * one in priv. + */ + qpls_alloc_cfg.qpl_cfg = &new_qpl_cfg; + tx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + rx_alloc_cfg.qpl_cfg = &new_qpl_cfg; + if ((netdev->features & NETIF_F_LRO) != (features & NETIF_F_LRO)) { netdev->features ^= NETIF_F_LRO; if (netif_carrier_ok(netdev)) { - /* To make this process as simple as possible we - * teardown the device, set the new configuration, - * and then bring the device up again. - */ - err = gve_close(netdev); - /* We have already tried to reset in close, just fail - * at this point. - */ - if (err) - goto err; - - err = gve_open(netdev); - if (err) - goto err; + err = gve_adjust_config(priv, &qpls_alloc_cfg, + &tx_alloc_cfg, &rx_alloc_cfg); + if (err) { + /* Revert the change on error. */ + netdev->features = orig_features; + return err; + } } } return 0; -err: - /* Reverts the change on error. */ - netdev->features = orig_features; - netif_err(priv, drv, netdev, - "Set features failed! !!! DISABLING ALL QUEUES !!!\n"); - return err; } static const struct net_device_ops gve_netdev_ops = { @@ -2051,6 +2264,8 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) goto err; } + priv->num_registered_pages = 0; + if (skip_describe_device) goto setup_device; @@ -2080,7 +2295,6 @@ static int gve_init_priv(struct gve_priv *priv, bool skip_describe_device) if (!gve_is_gqi(priv)) netif_set_tso_max_size(priv->dev, GVE_DQO_TX_MAX); - priv->num_registered_pages = 0; priv->rx_copybreak = GVE_DEFAULT_RX_COPYBREAK; /* gvnic has one Notification Block per MSI-x vector, except for the * management vector diff --git a/drivers/net/ethernet/google/gve/gve_rx.c b/drivers/net/ethernet/google/gve/gve_rx.c index 76615d47e055..20f5a9e7fae9 100644 --- a/drivers/net/ethernet/google/gve/gve_rx.c +++ b/drivers/net/ethernet/google/gve/gve_rx.c @@ -23,7 +23,9 @@ static void gve_rx_free_buffer(struct device *dev, gve_free_page(dev, page_info->page, dma, DMA_FROM_DEVICE); } -static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) +static void gve_rx_unfill_pages(struct gve_priv *priv, + struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { u32 slots = rx->mask + 1; int i; @@ -36,7 +38,7 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) for (i = 0; i < slots; i++) page_ref_sub(rx->data.page_info[i].page, rx->data.page_info[i].pagecnt_bias - 1); - gve_unassign_qpl(priv, rx->data.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id); rx->data.qpl = NULL; for (i = 0; i < rx->qpl_copy_pool_mask + 1; i++) { @@ -49,16 +51,26 @@ static void gve_rx_unfill_pages(struct gve_priv *priv, struct gve_rx_ring *rx) rx->data.page_info = NULL; } -static void gve_rx_free_ring(struct gve_priv *priv, int idx) +void gve_rx_stop_ring_gqi(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + if (!gve_rx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); +} + +static void gve_rx_free_ring_gqi(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *dev = &priv->pdev->dev; u32 slots = rx->mask + 1; + int idx = rx->q_num; size_t bytes; - gve_rx_remove_from_block(priv, idx); - - bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt; + bytes = sizeof(struct gve_rx_desc) * cfg->ring_size; dma_free_coherent(dev, bytes, rx->desc.desc_ring, rx->desc.bus); rx->desc.desc_ring = NULL; @@ -66,7 +78,7 @@ static void gve_rx_free_ring(struct gve_priv *priv, int idx) rx->q_resources, rx->q_resources_bus); rx->q_resources = NULL; - gve_rx_unfill_pages(priv, rx); + gve_rx_unfill_pages(priv, rx, cfg); bytes = sizeof(*rx->data.data_ring) * slots; dma_free_coherent(dev, bytes, rx->data.data_ring, @@ -93,7 +105,8 @@ static void gve_setup_rx_buffer(struct gve_rx_slot_page_info *page_info, static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev, struct gve_rx_slot_page_info *page_info, - union gve_rx_data_slot *data_slot) + union gve_rx_data_slot *data_slot, + struct gve_rx_ring *rx) { struct page *page; dma_addr_t dma; @@ -101,14 +114,19 @@ static int gve_rx_alloc_buffer(struct gve_priv *priv, struct device *dev, err = gve_alloc_page(priv, dev, &page, &dma, DMA_FROM_DEVICE, GFP_ATOMIC); - if (err) + if (err) { + u64_stats_update_begin(&rx->statss); + rx->rx_buf_alloc_fail++; + u64_stats_update_end(&rx->statss); return err; + } gve_setup_rx_buffer(page_info, dma, page, &data_slot->addr); return 0; } -static int gve_prefill_rx_pages(struct gve_rx_ring *rx) +static int gve_rx_prefill_pages(struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { struct gve_priv *priv = rx->gve; u32 slots; @@ -127,7 +145,7 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx) return -ENOMEM; if (!rx->data.raw_addressing) { - rx->data.qpl = gve_assign_rx_qpl(priv, rx->q_num); + rx->data.qpl = gve_assign_rx_qpl(cfg, rx->q_num); if (!rx->data.qpl) { kvfree(rx->data.page_info); rx->data.page_info = NULL; @@ -143,8 +161,9 @@ static int gve_prefill_rx_pages(struct gve_rx_ring *rx) &rx->data.data_ring[i].qpl_offset); continue; } - err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, &rx->data.page_info[i], - &rx->data.data_ring[i]); + err = gve_rx_alloc_buffer(priv, &priv->pdev->dev, + &rx->data.page_info[i], + &rx->data.data_ring[i], rx); if (err) goto alloc_err_rda; } @@ -185,7 +204,7 @@ alloc_err_qpl: page_ref_sub(rx->data.page_info[i].page, rx->data.page_info[i].pagecnt_bias - 1); - gve_unassign_qpl(priv, rx->data.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->data.qpl->id); rx->data.qpl = NULL; return err; @@ -207,13 +226,23 @@ static void gve_rx_ctx_clear(struct gve_rx_ctx *ctx) ctx->drop_pkt = false; } -static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) +void gve_rx_start_ring_gqi(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + gve_rx_add_to_block(priv, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll); +} + +static int gve_rx_alloc_ring_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg, + struct gve_rx_ring *rx, + int idx) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; + u32 slots = priv->rx_data_slot_cnt; int filled_pages; size_t bytes; - u32 slots; int err; netif_dbg(priv, drv, priv->dev, "allocating rx ring\n"); @@ -223,9 +252,8 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) rx->gve = priv; rx->q_num = idx; - slots = priv->rx_data_slot_cnt; rx->mask = slots - 1; - rx->data.raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT; + rx->data.raw_addressing = cfg->raw_addressing; /* alloc rx data ring */ bytes = sizeof(*rx->data.data_ring) * slots; @@ -246,7 +274,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) goto abort_with_slots; } - filled_pages = gve_prefill_rx_pages(rx); + filled_pages = gve_rx_prefill_pages(rx, cfg); if (filled_pages < 0) { err = -ENOMEM; goto abort_with_copy_pool; @@ -269,7 +297,7 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) (unsigned long)rx->data.data_bus); /* alloc rx desc ring */ - bytes = sizeof(struct gve_rx_desc) * priv->rx_desc_cnt; + bytes = sizeof(struct gve_rx_desc) * cfg->ring_size; rx->desc.desc_ring = dma_alloc_coherent(hdev, bytes, &rx->desc.bus, GFP_KERNEL); if (!rx->desc.desc_ring) { @@ -277,15 +305,11 @@ static int gve_rx_alloc_ring(struct gve_priv *priv, int idx) goto abort_with_q_resources; } rx->cnt = 0; - rx->db_threshold = priv->rx_desc_cnt / 2; + rx->db_threshold = slots / 2; rx->desc.seqno = 1; - /* Allocating half-page buffers allows page-flipping which is faster - * than copying or allocating new pages. - */ rx->packet_buffer_size = GVE_DEFAULT_RX_BUFFER_SIZE; gve_rx_ctx_clear(&rx->ctx); - gve_rx_add_to_block(priv, idx); return 0; @@ -294,7 +318,7 @@ abort_with_q_resources: rx->q_resources, rx->q_resources_bus); rx->q_resources = NULL; abort_filled: - gve_rx_unfill_pages(priv, rx); + gve_rx_unfill_pages(priv, rx, cfg); abort_with_copy_pool: kvfree(rx->qpl_copy_pool); rx->qpl_copy_pool = NULL; @@ -306,36 +330,58 @@ abort_with_slots: return err; } -int gve_rx_alloc_rings(struct gve_priv *priv) +int gve_rx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx; int err = 0; - int i; + int i, j; + + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - err = gve_rx_alloc_ring(priv, i); + rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring), + GFP_KERNEL); + if (!rx) + return -ENOMEM; + + for (i = 0; i < cfg->qcfg->num_queues; i++) { + err = gve_rx_alloc_ring_gqi(priv, cfg, &rx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc rx ring=%d: err=%d\n", i, err); - break; + goto cleanup; } } - /* Unallocate if there was an error */ - if (err) { - int j; - for (j = 0; j < i; j++) - gve_rx_free_ring(priv, j); - } + cfg->rx = rx; + return 0; + +cleanup: + for (j = 0; j < i; j++) + gve_rx_free_ring_gqi(priv, &rx[j], cfg); + kvfree(rx); return err; } -void gve_rx_free_rings_gqi(struct gve_priv *priv) +void gve_rx_free_rings_gqi(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx = cfg->rx; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) - gve_rx_free_ring(priv, i); + if (!rx) + return; + + for (i = 0; i < cfg->qcfg->num_queues; i++) + gve_rx_free_ring_gqi(priv, &rx[i], cfg); + + kvfree(rx); + cfg->rx = NULL; } void gve_rx_write_doorbell(struct gve_priv *priv, struct gve_rx_ring *rx) @@ -896,10 +942,7 @@ static bool gve_rx_refill_buffers(struct gve_priv *priv, struct gve_rx_ring *rx) gve_rx_free_buffer(dev, page_info, data_slot); page_info->page = NULL; if (gve_rx_alloc_buffer(priv, dev, page_info, - data_slot)) { - u64_stats_update_begin(&rx->statss); - rx->rx_buf_alloc_fail++; - u64_stats_update_end(&rx->statss); + data_slot, rx)) { break; } } diff --git a/drivers/net/ethernet/google/gve/gve_rx_dqo.c b/drivers/net/ethernet/google/gve/gve_rx_dqo.c index f281e42a7ef9..8e6aeb5b3ed4 100644 --- a/drivers/net/ethernet/google/gve/gve_rx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_rx_dqo.c @@ -199,20 +199,30 @@ static int gve_alloc_page_dqo(struct gve_rx_ring *rx, return 0; } -static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) +void gve_rx_stop_ring_dqo(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + if (!gve_rx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_rx_remove_from_block(priv, idx); +} + +static void gve_rx_free_ring_dqo(struct gve_priv *priv, struct gve_rx_ring *rx, + struct gve_rx_alloc_rings_cfg *cfg) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; size_t completion_queue_slots; size_t buffer_queue_slots; + int idx = rx->q_num; size_t size; int i; completion_queue_slots = rx->dqo.complq.mask + 1; buffer_queue_slots = rx->dqo.bufq.mask + 1; - gve_rx_remove_from_block(priv, idx); - if (rx->q_resources) { dma_free_coherent(hdev, sizeof(*rx->q_resources), rx->q_resources, rx->q_resources_bus); @@ -226,7 +236,7 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) gve_free_page_dqo(priv, bs, !rx->dqo.qpl); } if (rx->dqo.qpl) { - gve_unassign_qpl(priv, rx->dqo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, rx->dqo.qpl->id); rx->dqo.qpl = NULL; } @@ -251,17 +261,26 @@ static void gve_rx_free_ring_dqo(struct gve_priv *priv, int idx) netif_dbg(priv, drv, priv->dev, "freed rx ring %d\n", idx); } -static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) +void gve_rx_start_ring_dqo(struct gve_priv *priv, int idx) +{ + int ntfy_idx = gve_rx_idx_to_ntfy(priv, idx); + + gve_rx_add_to_block(priv, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); +} + +static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg, + struct gve_rx_ring *rx, + int idx) { - struct gve_rx_ring *rx = &priv->rx[idx]; struct device *hdev = &priv->pdev->dev; size_t size; int i; - const u32 buffer_queue_slots = - priv->queue_format == GVE_DQO_RDA_FORMAT ? - priv->options_dqo_rda.rx_buff_ring_entries : priv->rx_desc_cnt; - const u32 completion_queue_slots = priv->rx_desc_cnt; + const u32 buffer_queue_slots = cfg->raw_addressing ? + priv->options_dqo_rda.rx_buff_ring_entries : cfg->ring_size; + const u32 completion_queue_slots = cfg->ring_size; netif_dbg(priv, drv, priv->dev, "allocating rx ring DQO\n"); @@ -274,7 +293,7 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) rx->ctx.skb_head = NULL; rx->ctx.skb_tail = NULL; - rx->dqo.num_buf_states = priv->queue_format == GVE_DQO_RDA_FORMAT ? + rx->dqo.num_buf_states = cfg->raw_addressing ? min_t(s16, S16_MAX, buffer_queue_slots * 4) : priv->rx_pages_per_qpl; rx->dqo.buf_states = kvcalloc(rx->dqo.num_buf_states, @@ -308,8 +327,8 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!rx->dqo.bufq.desc_ring) goto err; - if (priv->queue_format != GVE_DQO_RDA_FORMAT) { - rx->dqo.qpl = gve_assign_rx_qpl(priv, rx->q_num); + if (!cfg->raw_addressing) { + rx->dqo.qpl = gve_assign_rx_qpl(cfg, rx->q_num); if (!rx->dqo.qpl) goto err; rx->dqo.next_qpl_page_idx = 0; @@ -320,12 +339,10 @@ static int gve_rx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!rx->q_resources) goto err; - gve_rx_add_to_block(priv, idx); - return 0; err: - gve_rx_free_ring_dqo(priv, idx); + gve_rx_free_ring_dqo(priv, rx, cfg); return -ENOMEM; } @@ -337,13 +354,26 @@ void gve_rx_write_doorbell_dqo(const struct gve_priv *priv, int queue_idx) iowrite32(rx->dqo.bufq.tail, &priv->db_bar2[index]); } -int gve_rx_alloc_rings_dqo(struct gve_priv *priv) +int gve_rx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { - int err = 0; + struct gve_rx_ring *rx; + int err; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) { - err = gve_rx_alloc_ring_dqo(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + rx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_rx_ring), + GFP_KERNEL); + if (!rx) + return -ENOMEM; + + for (i = 0; i < cfg->qcfg->num_queues; i++) { + err = gve_rx_alloc_ring_dqo(priv, cfg, &rx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc rx ring=%d: err=%d\n", @@ -352,21 +382,30 @@ int gve_rx_alloc_rings_dqo(struct gve_priv *priv) } } + cfg->rx = rx; return 0; err: for (i--; i >= 0; i--) - gve_rx_free_ring_dqo(priv, i); - + gve_rx_free_ring_dqo(priv, &rx[i], cfg); + kvfree(rx); return err; } -void gve_rx_free_rings_dqo(struct gve_priv *priv) +void gve_rx_free_rings_dqo(struct gve_priv *priv, + struct gve_rx_alloc_rings_cfg *cfg) { + struct gve_rx_ring *rx = cfg->rx; int i; - for (i = 0; i < priv->rx_cfg.num_queues; i++) - gve_rx_free_ring_dqo(priv, i); + if (!rx) + return; + + for (i = 0; i < cfg->qcfg->num_queues; i++) + gve_rx_free_ring_dqo(priv, &rx[i], cfg); + + kvfree(rx); + cfg->rx = NULL; } void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) diff --git a/drivers/net/ethernet/google/gve/gve_tx.c b/drivers/net/ethernet/google/gve/gve_tx.c index 07ba124780df..4b9853adc113 100644 --- a/drivers/net/ethernet/google/gve/gve_tx.c +++ b/drivers/net/ethernet/google/gve/gve_tx.c @@ -196,29 +196,36 @@ static int gve_clean_xdp_done(struct gve_priv *priv, struct gve_tx_ring *tx, static int gve_clean_tx_done(struct gve_priv *priv, struct gve_tx_ring *tx, u32 to_do, bool try_to_wake); -static void gve_tx_free_ring(struct gve_priv *priv, int idx) +void gve_tx_stop_ring_gqi(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + if (!gve_tx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false); + netdev_tx_reset_queue(tx->netdev_txq); + gve_tx_remove_from_block(priv, idx); +} + +static void gve_tx_free_ring_gqi(struct gve_priv *priv, struct gve_tx_ring *tx, + struct gve_tx_alloc_rings_cfg *cfg) +{ struct device *hdev = &priv->pdev->dev; + int idx = tx->q_num; size_t bytes; u32 slots; - gve_tx_remove_from_block(priv, idx); slots = tx->mask + 1; - if (tx->q_num < priv->tx_cfg.num_queues) { - gve_clean_tx_done(priv, tx, priv->tx_desc_cnt, false); - netdev_tx_reset_queue(tx->netdev_txq); - } else { - gve_clean_xdp_done(priv, tx, priv->tx_desc_cnt); - } - dma_free_coherent(hdev, sizeof(*tx->q_resources), tx->q_resources, tx->q_resources_bus); tx->q_resources = NULL; if (!tx->raw_addressing) { gve_tx_fifo_release(priv, &tx->tx_fifo); - gve_unassign_qpl(priv, tx->tx_fifo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id); tx->tx_fifo.qpl = NULL; } @@ -232,11 +239,23 @@ static void gve_tx_free_ring(struct gve_priv *priv, int idx) netif_dbg(priv, drv, priv->dev, "freed tx queue %d\n", idx); } -static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) +void gve_tx_start_ring_gqi(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + gve_tx_add_to_block(priv, idx); + + tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll); +} + +static int gve_tx_alloc_ring_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg, + struct gve_tx_ring *tx, + int idx) +{ struct device *hdev = &priv->pdev->dev; - u32 slots = priv->tx_desc_cnt; size_t bytes; /* Make sure everything is zeroed to start */ @@ -245,23 +264,23 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) spin_lock_init(&tx->xdp_lock); tx->q_num = idx; - tx->mask = slots - 1; + tx->mask = cfg->ring_size - 1; /* alloc metadata */ - tx->info = vcalloc(slots, sizeof(*tx->info)); + tx->info = vcalloc(cfg->ring_size, sizeof(*tx->info)); if (!tx->info) return -ENOMEM; /* alloc tx queue */ - bytes = sizeof(*tx->desc) * slots; + bytes = sizeof(*tx->desc) * cfg->ring_size; tx->desc = dma_alloc_coherent(hdev, bytes, &tx->bus, GFP_KERNEL); if (!tx->desc) goto abort_with_info; - tx->raw_addressing = priv->queue_format == GVE_GQI_RDA_FORMAT; - tx->dev = &priv->pdev->dev; + tx->raw_addressing = cfg->raw_addressing; + tx->dev = hdev; if (!tx->raw_addressing) { - tx->tx_fifo.qpl = gve_assign_tx_qpl(priv, idx); + tx->tx_fifo.qpl = gve_assign_tx_qpl(cfg, idx); if (!tx->tx_fifo.qpl) goto abort_with_desc; /* map Tx FIFO */ @@ -277,12 +296,6 @@ static int gve_tx_alloc_ring(struct gve_priv *priv, int idx) if (!tx->q_resources) goto abort_with_fifo; - netif_dbg(priv, drv, priv->dev, "tx[%d]->bus=%lx\n", idx, - (unsigned long)tx->bus); - if (idx < priv->tx_cfg.num_queues) - tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); - gve_tx_add_to_block(priv, idx); - return 0; abort_with_fifo: @@ -290,7 +303,7 @@ abort_with_fifo: gve_tx_fifo_release(priv, &tx->tx_fifo); abort_with_qpl: if (!tx->raw_addressing) - gve_unassign_qpl(priv, tx->tx_fifo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->tx_fifo.qpl->id); abort_with_desc: dma_free_coherent(hdev, bytes, tx->desc, tx->bus); tx->desc = NULL; @@ -300,36 +313,73 @@ abort_with_info: return -ENOMEM; } -int gve_tx_alloc_rings(struct gve_priv *priv, int start_id, int num_rings) +int gve_tx_alloc_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int err = 0; - int i; + int i, j; + + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) { + netif_err(priv, drv, priv->dev, + "Cannot alloc more than the max num of Tx rings\n"); + return -EINVAL; + } + + if (cfg->start_idx == 0) { + tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring), + GFP_KERNEL); + if (!tx) + return -ENOMEM; + } else if (!tx) { + netif_err(priv, drv, priv->dev, + "Cannot alloc tx rings from a nonzero start idx without tx array\n"); + return -EINVAL; + } - for (i = start_id; i < start_id + num_rings; i++) { - err = gve_tx_alloc_ring(priv, i); + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) { + err = gve_tx_alloc_ring_gqi(priv, cfg, &tx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc tx ring=%d: err=%d\n", i, err); - break; + goto cleanup; } } - /* Unallocate if there was an error */ - if (err) { - int j; - for (j = start_id; j < i; j++) - gve_tx_free_ring(priv, j); - } + cfg->tx = tx; + return 0; + +cleanup: + for (j = 0; j < i; j++) + gve_tx_free_ring_gqi(priv, &tx[j], cfg); + if (cfg->start_idx == 0) + kvfree(tx); return err; } -void gve_tx_free_rings_gqi(struct gve_priv *priv, int start_id, int num_rings) +void gve_tx_free_rings_gqi(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int i; - for (i = start_id; i < start_id + num_rings; i++) - gve_tx_free_ring(priv, i); + if (!tx) + return; + + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) + gve_tx_free_ring_gqi(priv, &tx[i], cfg); + + if (cfg->start_idx == 0) { + kvfree(tx); + cfg->tx = NULL; + } } /* gve_tx_avail - Calculates the number of slots available in the ring diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index f59c4710f118..bc34b6cd3a3e 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -188,13 +188,27 @@ static void gve_tx_clean_pending_packets(struct gve_tx_ring *tx) } } -static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx) +void gve_tx_stop_ring_dqo(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; - struct device *hdev = &priv->pdev->dev; - size_t bytes; + if (!gve_tx_was_added_to_block(priv, idx)) + return; + + gve_remove_napi(priv, ntfy_idx); + gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL); + netdev_tx_reset_queue(tx->netdev_txq); + gve_tx_clean_pending_packets(tx); gve_tx_remove_from_block(priv, idx); +} + +static void gve_tx_free_ring_dqo(struct gve_priv *priv, struct gve_tx_ring *tx, + struct gve_tx_alloc_rings_cfg *cfg) +{ + struct device *hdev = &priv->pdev->dev; + int idx = tx->q_num; + size_t bytes; if (tx->q_resources) { dma_free_coherent(hdev, sizeof(*tx->q_resources), @@ -223,7 +237,7 @@ static void gve_tx_free_ring_dqo(struct gve_priv *priv, int idx) tx->dqo.tx_qpl_buf_next = NULL; if (tx->dqo.qpl) { - gve_unassign_qpl(priv, tx->dqo.qpl->id); + gve_unassign_qpl(cfg->qpl_cfg, tx->dqo.qpl->id); tx->dqo.qpl = NULL; } @@ -253,9 +267,22 @@ static int gve_tx_qpl_buf_init(struct gve_tx_ring *tx) return 0; } -static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) +void gve_tx_start_ring_dqo(struct gve_priv *priv, int idx) { + int ntfy_idx = gve_tx_idx_to_ntfy(priv, idx); struct gve_tx_ring *tx = &priv->tx[idx]; + + gve_tx_add_to_block(priv, idx); + + tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + gve_add_napi(priv, ntfy_idx, gve_napi_poll_dqo); +} + +static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg, + struct gve_tx_ring *tx, + int idx) +{ struct device *hdev = &priv->pdev->dev; int num_pending_packets; size_t bytes; @@ -263,12 +290,11 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) memset(tx, 0, sizeof(*tx)); tx->q_num = idx; - tx->dev = &priv->pdev->dev; - tx->netdev_txq = netdev_get_tx_queue(priv->dev, idx); + tx->dev = hdev; atomic_set_release(&tx->dqo_compl.hw_tx_head, 0); /* Queue sizes must be a power of 2 */ - tx->mask = priv->tx_desc_cnt - 1; + tx->mask = cfg->ring_size - 1; tx->dqo.complq_mask = priv->queue_format == GVE_DQO_RDA_FORMAT ? priv->options_dqo_rda.tx_comp_ring_entries - 1 : tx->mask; @@ -327,8 +353,8 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) if (!tx->q_resources) goto err; - if (gve_is_qpl(priv)) { - tx->dqo.qpl = gve_assign_tx_qpl(priv, idx); + if (!cfg->raw_addressing) { + tx->dqo.qpl = gve_assign_tx_qpl(cfg, idx); if (!tx->dqo.qpl) goto err; @@ -336,22 +362,45 @@ static int gve_tx_alloc_ring_dqo(struct gve_priv *priv, int idx) goto err; } - gve_tx_add_to_block(priv, idx); - return 0; err: - gve_tx_free_ring_dqo(priv, idx); + gve_tx_free_ring_dqo(priv, tx, cfg); return -ENOMEM; } -int gve_tx_alloc_rings_dqo(struct gve_priv *priv) +int gve_tx_alloc_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int err = 0; - int i; + int i, j; - for (i = 0; i < priv->tx_cfg.num_queues; i++) { - err = gve_tx_alloc_ring_dqo(priv, i); + if (!cfg->raw_addressing && !cfg->qpls) { + netif_err(priv, drv, priv->dev, + "Cannot alloc QPL ring before allocing QPLs\n"); + return -EINVAL; + } + + if (cfg->start_idx + cfg->num_rings > cfg->qcfg->max_queues) { + netif_err(priv, drv, priv->dev, + "Cannot alloc more than the max num of Tx rings\n"); + return -EINVAL; + } + + if (cfg->start_idx == 0) { + tx = kvcalloc(cfg->qcfg->max_queues, sizeof(struct gve_tx_ring), + GFP_KERNEL); + if (!tx) + return -ENOMEM; + } else if (!tx) { + netif_err(priv, drv, priv->dev, + "Cannot alloc tx rings from a nonzero start idx without tx array\n"); + return -EINVAL; + } + + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) { + err = gve_tx_alloc_ring_dqo(priv, cfg, &tx[i], i); if (err) { netif_err(priv, drv, priv->dev, "Failed to alloc tx ring=%d: err=%d\n", @@ -360,27 +409,32 @@ int gve_tx_alloc_rings_dqo(struct gve_priv *priv) } } + cfg->tx = tx; return 0; err: - for (i--; i >= 0; i--) - gve_tx_free_ring_dqo(priv, i); - + for (j = 0; j < i; j++) + gve_tx_free_ring_dqo(priv, &tx[j], cfg); + if (cfg->start_idx == 0) + kvfree(tx); return err; } -void gve_tx_free_rings_dqo(struct gve_priv *priv) +void gve_tx_free_rings_dqo(struct gve_priv *priv, + struct gve_tx_alloc_rings_cfg *cfg) { + struct gve_tx_ring *tx = cfg->tx; int i; - for (i = 0; i < priv->tx_cfg.num_queues; i++) { - struct gve_tx_ring *tx = &priv->tx[i]; + if (!tx) + return; - gve_clean_tx_done_dqo(priv, tx, /*napi=*/NULL); - netdev_tx_reset_queue(tx->netdev_txq); - gve_tx_clean_pending_packets(tx); + for (i = cfg->start_idx; i < cfg->start_idx + cfg->num_rings; i++) + gve_tx_free_ring_dqo(priv, &tx[i], cfg); - gve_tx_free_ring_dqo(priv, i); + if (cfg->start_idx == 0) { + kvfree(tx); + cfg->tx = NULL; } } diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index 26e08d753270..535b1796b91d 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -8,6 +8,14 @@ #include "gve_adminq.h" #include "gve_utils.h" +bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx) +{ + struct gve_notify_block *block = + &priv->ntfy_blocks[gve_tx_idx_to_ntfy(priv, queue_idx)]; + + return block->tx != NULL; +} + void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx) { struct gve_notify_block *block = @@ -30,6 +38,14 @@ void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx) queue_idx); } +bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx) +{ + struct gve_notify_block *block = + &priv->ntfy_blocks[gve_rx_idx_to_ntfy(priv, queue_idx)]; + + return block->rx != NULL; +} + void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx) { struct gve_notify_block *block = @@ -81,3 +97,18 @@ void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info) page_ref_add(page_info->page, INT_MAX - pagecount); } } + +void gve_add_napi(struct gve_priv *priv, int ntfy_idx, + int (*gve_poll)(struct napi_struct *, int)) +{ + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + + netif_napi_add(priv->dev, &block->napi, gve_poll); +} + +void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) +{ + struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + + netif_napi_del(&block->napi); +} diff --git a/drivers/net/ethernet/google/gve/gve_utils.h b/drivers/net/ethernet/google/gve/gve_utils.h index 324fd98a6112..277921a629f7 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.h +++ b/drivers/net/ethernet/google/gve/gve_utils.h @@ -11,9 +11,11 @@ #include "gve.h" +bool gve_tx_was_added_to_block(struct gve_priv *priv, int queue_idx); void gve_tx_remove_from_block(struct gve_priv *priv, int queue_idx); void gve_tx_add_to_block(struct gve_priv *priv, int queue_idx); +bool gve_rx_was_added_to_block(struct gve_priv *priv, int queue_idx); void gve_rx_remove_from_block(struct gve_priv *priv, int queue_idx); void gve_rx_add_to_block(struct gve_priv *priv, int queue_idx); @@ -23,5 +25,8 @@ struct sk_buff *gve_rx_copy(struct net_device *dev, struct napi_struct *napi, /* Decrement pagecnt_bias. Set it back to INT_MAX if it reached zero. */ void gve_dec_pagecnt_bias(struct gve_rx_slot_page_info *page_info); +void gve_add_napi(struct gve_priv *priv, int ntfy_idx, + int (*gve_poll)(struct napi_struct *, int)); +void gve_remove_napi(struct gve_priv *priv, int ntfy_idx); #endif /* _GVE_UTILS_H */ diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index fc0f98ea6133..ff243ae71b78 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -2186,7 +2186,7 @@ static int e1000_get_rxnfc(struct net_device *netdev, } } -static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int e1000e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; @@ -2223,16 +2223,16 @@ static int e1000e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) ret_val = e1000_read_emi_reg_locked(hw, cap_addr, &phy_data); if (ret_val) goto release; - edata->supported = mmd_eee_cap_to_ethtool_sup_t(phy_data); + edata->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(phy_data); /* EEE Advertised */ - edata->advertised = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); /* EEE Link Partner Advertised */ ret_val = e1000_read_emi_reg_locked(hw, lpa_addr, &phy_data); if (ret_val) goto release; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); /* EEE PCS Status */ ret_val = e1000_read_emi_reg_locked(hw, pcs_stat_addr, &phy_data); @@ -2262,11 +2262,11 @@ release: return ret_val; } -static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int e1000e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; s32 ret_val; ret_val = e1000e_get_eee(netdev, &eee_curr); @@ -2283,12 +2283,12 @@ static int e1000e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) return -EINVAL; } - if (edata->advertised & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { + if (edata->advertised_u32 & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL)) { e_err("EEE advertisement supports only 100TX and/or 1000T full-duplex\n"); return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); hw->dev_spec.ich8lan.eee_disable = !edata->eee_enabled; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index c841779713f6..1b5473358e1a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -5644,7 +5644,7 @@ static int i40e_get_module_eeprom(struct net_device *netdev, return 0; } -static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int i40e_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_aq_get_phy_abilities_resp phy_cfg; @@ -5664,16 +5664,16 @@ static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) if (phy_cfg.eee_capability == 0) return -EOPNOTSUPP; - edata->supported = SUPPORTED_Autoneg; - edata->lp_advertised = edata->supported; + edata->supported_u32 = SUPPORTED_Autoneg; + edata->lp_advertised_u32 = edata->supported_u32; /* Get current configuration */ status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_cfg, NULL); if (status) return -EAGAIN; - edata->advertised = phy_cfg.eee_capability ? SUPPORTED_Autoneg : 0U; - edata->eee_enabled = !!edata->advertised; + edata->advertised_u32 = phy_cfg.eee_capability ? SUPPORTED_Autoneg : 0U; + edata->eee_enabled = !!edata->advertised_u32; edata->tx_lpi_enabled = pf->stats.tx_lpi_status; edata->eee_active = pf->stats.tx_lpi_status && pf->stats.rx_lpi_status; @@ -5682,7 +5682,7 @@ static int i40e_get_eee(struct net_device *netdev, struct ethtool_eee *edata) } static int i40e_is_eee_param_supported(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_vsi *vsi = np->vsi; @@ -5691,7 +5691,7 @@ static int i40e_is_eee_param_supported(struct net_device *netdev, u32 value; const char *name; } param[] = { - {edata->advertised & ~SUPPORTED_Autoneg, "advertise"}, + {edata->advertised_u32 & ~SUPPORTED_Autoneg, "advertise"}, {edata->tx_lpi_timer, "tx-timer"}, {edata->tx_lpi_enabled != pf->stats.tx_lpi_status, "tx-lpi"} }; @@ -5709,7 +5709,7 @@ static int i40e_is_eee_param_supported(struct net_device *netdev, return 0; } -static int i40e_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int i40e_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_aq_get_phy_abilities_resp abilities; diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 367b613d92c0..97c2a5fb5dbf 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -493,7 +493,6 @@ enum ice_pf_flags { ICE_FLAG_DCB_ENA, ICE_FLAG_FD_ENA, ICE_FLAG_PTP_SUPPORTED, /* PTP is supported by NVM */ - ICE_FLAG_PTP, /* PTP is enabled by software */ ICE_FLAG_ADV_FEATURES, ICE_FLAG_TC_MQPRIO, /* support for Multi queue TC */ ICE_FLAG_CLS_FLOWER, diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c b/drivers/net/ethernet/intel/ice/ice_dpll.c index b9c5eced6326..c0256564e998 100644 --- a/drivers/net/ethernet/intel/ice/ice_dpll.c +++ b/drivers/net/ethernet/intel/ice/ice_dpll.c @@ -488,6 +488,7 @@ ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, * @dpll: registered dpll pointer * @dpll_priv: private data pointer passed on dpll registration * @status: on success holds dpll's lock status + * @status_error: status error value * @extack: error reporting * * Dpll subsystem callback, provides dpll's lock status. @@ -500,6 +501,7 @@ ice_dpll_hw_input_prio_set(struct ice_pf *pf, struct ice_dpll *dpll, static int ice_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv, enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, struct netlink_ext_ack *extack) { struct ice_dpll *d = dpll_priv; diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index a19b06f18e40..55fcf17d503e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -3360,7 +3360,7 @@ ice_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) struct ice_pf *pf = ice_netdev_to_pf(dev); /* only report timestamping if PTP is enabled */ - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return ethtool_op_get_ts_info(dev, info); info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index dd4a9bc0dfdc..2b7960824bc3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -613,7 +613,7 @@ skip: ice_pf_dis_all_vsi(pf, false); if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) - ice_ptp_prepare_for_reset(pf); + ice_ptp_prepare_for_reset(pf, reset_type); if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_exit(pf); @@ -7548,7 +7548,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) * fail. */ if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags)) - ice_ptp_reset(pf); + ice_ptp_rebuild(pf, reset_type); if (ice_is_feature_supported(pf, ICE_F_GNSS)) ice_gnss_init(pf); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 3b6605c8585e..c11eba07283c 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -601,17 +601,13 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) /* Read the low 32 bit value */ raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH); - /* For PHYs which don't implement a proper timestamp ready bitmap, - * verify that the timestamp value is different from the last cached - * timestamp. If it is not, skip this for now assuming it hasn't yet - * been captured by hardware. + /* Devices using this interface always verify the timestamp differs + * relative to the last cached timestamp value. */ - if (!drop_ts && tx->verify_cached && - raw_tstamp == tx->tstamps[idx].cached_tstamp) + if (raw_tstamp == tx->tstamps[idx].cached_tstamp) return; - if (tx->verify_cached && raw_tstamp) - tx->tstamps[idx].cached_tstamp = raw_tstamp; + tx->tstamps[idx].cached_tstamp = raw_tstamp; clear_bit(idx, tx->in_use); skb = tx->tstamps[idx].skb; tx->tstamps[idx].skb = NULL; @@ -701,9 +697,11 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) hw = &pf->hw; /* Read the Tx ready status first */ - err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready); - if (err) - return; + if (tx->has_ready_bitmap) { + err = ice_get_phy_tx_tstamp_ready(hw, tx->block, &tstamp_ready); + if (err) + return; + } /* Drop packets if the link went down */ link_up = ptp_port->link_up; @@ -731,7 +729,8 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) * If we do not, the hardware logic for generating a new * interrupt can get stuck on some devices. */ - if (!(tstamp_ready & BIT_ULL(phy_idx))) { + if (tx->has_ready_bitmap && + !(tstamp_ready & BIT_ULL(phy_idx))) { if (drop_ts) goto skip_ts_read; @@ -751,7 +750,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) * from the last cached timestamp. If it is not, skip this for * now assuming it hasn't yet been captured by hardware. */ - if (!drop_ts && tx->verify_cached && + if (!drop_ts && !tx->has_ready_bitmap && raw_tstamp == tx->tstamps[idx].cached_tstamp) continue; @@ -761,7 +760,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) skip_ts_read: spin_lock_irqsave(&tx->lock, flags); - if (tx->verify_cached && raw_tstamp) + if (!tx->has_ready_bitmap && raw_tstamp) tx->tstamps[idx].cached_tstamp = raw_tstamp; clear_bit(idx, tx->in_use); skb = tx->tstamps[idx].skb; @@ -965,6 +964,22 @@ ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx) } /** + * ice_ptp_flush_all_tx_tracker - Flush all timestamp trackers on this clock + * @pf: Board private structure + * + * Called by the clock owner to flush all the Tx timestamp trackers associated + * with the clock. + */ +static void +ice_ptp_flush_all_tx_tracker(struct ice_pf *pf) +{ + struct ice_ptp_port *port; + + list_for_each_entry(port, &pf->ptp.ports_owner.ports, list_member) + ice_ptp_flush_tx_tracker(ptp_port_to_pf(port), &port->tx); +} + +/** * ice_ptp_release_tx_tracker - Release allocated memory for Tx tracker * @pf: Board private structure * @tx: Tx tracking structure to release @@ -1014,7 +1029,7 @@ ice_ptp_init_tx_e82x(struct ice_pf *pf, struct ice_ptp_tx *tx, u8 port) tx->block = port / ICE_PORTS_PER_QUAD; tx->offset = (port % ICE_PORTS_PER_QUAD) * INDEX_PER_PORT_E82X; tx->len = INDEX_PER_PORT_E82X; - tx->verify_cached = 0; + tx->has_ready_bitmap = 1; return ice_ptp_alloc_tx_tracker(tx); } @@ -1037,7 +1052,7 @@ ice_ptp_init_tx_e810(struct ice_pf *pf, struct ice_ptp_tx *tx) * verify new timestamps against cached copy of the last read * timestamp. */ - tx->verify_cached = 1; + tx->has_ready_bitmap = 0; return ice_ptp_alloc_tx_tracker(tx); } @@ -1430,7 +1445,7 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) struct ice_ptp_port *ptp_port; struct ice_hw *hw = &pf->hw; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; if (WARN_ON_ONCE(port >= ICE_NUM_EXTERNAL_PORTS)) @@ -1456,14 +1471,14 @@ void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) } /** - * ice_ptp_tx_ena_intr - Enable or disable the Tx timestamp interrupt + * ice_ptp_cfg_phy_interrupt - Configure PHY interrupt settings * @pf: PF private structure * @ena: bool value to enable or disable interrupt * @threshold: Minimum number of packets at which intr is triggered * * Utility function to enable or disable Tx timestamp interrupt and threshold */ -static int ice_ptp_tx_ena_intr(struct ice_pf *pf, bool ena, u32 threshold) +static int ice_ptp_cfg_phy_interrupt(struct ice_pf *pf, bool ena, u32 threshold) { struct ice_hw *hw = &pf->hw; int err = 0; @@ -2162,7 +2177,7 @@ int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) { struct hwtstamp_config *config; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return -EIO; config = &pf->ptp.tstamp_config; @@ -2232,7 +2247,7 @@ int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) struct hwtstamp_config config; int err; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return -EAGAIN; if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) @@ -2616,7 +2631,7 @@ static void ice_ptp_periodic_work(struct kthread_work *work) struct ice_pf *pf = container_of(ptp, struct ice_pf, ptp); int err; - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; err = ice_ptp_update_cached_phctime(pf); @@ -2629,36 +2644,72 @@ static void ice_ptp_periodic_work(struct kthread_work *work) } /** - * ice_ptp_reset - Initialize PTP hardware clock support after reset + * ice_ptp_prepare_for_reset - Prepare PTP for reset + * @pf: Board private structure + * @reset_type: the reset type being performed + */ +void ice_ptp_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type) +{ + struct ice_ptp *ptp = &pf->ptp; + u8 src_tmr; + + if (ptp->state != ICE_PTP_READY) + return; + + ptp->state = ICE_PTP_RESETTING; + + /* Disable timestamping for both Tx and Rx */ + ice_ptp_disable_timestamp_mode(pf); + + kthread_cancel_delayed_work_sync(&ptp->work); + + if (reset_type == ICE_RESET_PFR) + return; + + ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); + + /* Disable periodic outputs */ + ice_ptp_disable_all_clkout(pf); + + src_tmr = ice_get_ptp_src_clock_index(&pf->hw); + + /* Disable source clock */ + wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M); + + /* Acquire PHC and system timer to restore after reset */ + ptp->reset_time = ktime_get_real_ns(); +} + +/** + * ice_ptp_rebuild_owner - Initialize PTP clock owner after reset * @pf: Board private structure + * + * Companion function for ice_ptp_rebuild() which handles tasks that only the + * PTP clock owner instance should perform. */ -void ice_ptp_reset(struct ice_pf *pf) +static int ice_ptp_rebuild_owner(struct ice_pf *pf) { struct ice_ptp *ptp = &pf->ptp; struct ice_hw *hw = &pf->hw; struct timespec64 ts; - int err, itr = 1; u64 time_diff; - - if (test_bit(ICE_PFR_REQ, pf->state) || - !ice_pf_src_tmr_owned(pf)) - goto pfr; + int err; err = ice_ptp_init_phc(hw); if (err) - goto err; + return err; /* Acquire the global hardware lock */ if (!ice_ptp_lock(hw)) { err = -EBUSY; - goto err; + return err; } /* Write the increment time value to PHY and LAN */ err = ice_ptp_write_incval(hw, ice_base_incval(pf)); if (err) { ice_ptp_unlock(hw); - goto err; + return err; } /* Write the initial Time value to PHY and LAN using the cached PHC @@ -2674,38 +2725,54 @@ void ice_ptp_reset(struct ice_pf *pf) err = ice_ptp_write_init(pf, &ts); if (err) { ice_ptp_unlock(hw); - goto err; + return err; } /* Release the global hardware lock */ ice_ptp_unlock(hw); + /* Flush software tracking of any outstanding timestamps since we're + * about to flush the PHY timestamp block. + */ + ice_ptp_flush_all_tx_tracker(pf); + if (!ice_is_e810(hw)) { /* Enable quad interrupts */ - err = ice_ptp_tx_ena_intr(pf, true, itr); + err = ice_ptp_cfg_phy_interrupt(pf, true, 1); if (err) - goto err; - } + return err; -pfr: - /* Init Tx structures */ - if (ice_is_e810(&pf->hw)) { - err = ice_ptp_init_tx_e810(pf, &ptp->port.tx); - } else { - kthread_init_delayed_work(&ptp->port.ov_work, - ice_ptp_wait_for_offsets); - err = ice_ptp_init_tx_e82x(pf, &ptp->port.tx, - ptp->port.port_num); + ice_ptp_restart_all_phy(pf); } - if (err) + + return 0; +} + +/** + * ice_ptp_rebuild - Initialize PTP hardware clock support after reset + * @pf: Board private structure + * @reset_type: the reset type being performed + */ +void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) +{ + struct ice_ptp *ptp = &pf->ptp; + int err; + + if (ptp->state == ICE_PTP_READY) { + ice_ptp_prepare_for_reset(pf, reset_type); + } else if (ptp->state != ICE_PTP_RESETTING) { + err = -EINVAL; + dev_err(ice_pf_to_dev(pf), "PTP was not initialized\n"); goto err; + } - set_bit(ICE_FLAG_PTP, pf->flags); + if (ice_pf_src_tmr_owned(pf) && reset_type != ICE_RESET_PFR) { + err = ice_ptp_rebuild_owner(pf); + if (err) + goto err; + } - /* Restart the PHY timestamping block */ - if (!test_bit(ICE_PFR_REQ, pf->state) && - ice_pf_src_tmr_owned(pf)) - ice_ptp_restart_all_phy(pf); + ptp->state = ICE_PTP_READY; /* Start periodic work going */ kthread_queue_delayed_work(ptp->kworker, &ptp->work, 0); @@ -2714,6 +2781,7 @@ pfr: return; err: + ptp->state = ICE_PTP_ERROR; dev_err(ice_pf_to_dev(pf), "PTP reset failed %d\n", err); } @@ -2923,39 +2991,6 @@ int ice_ptp_clock_index(struct ice_pf *pf) } /** - * ice_ptp_prepare_for_reset - Prepare PTP for reset - * @pf: Board private structure - */ -void ice_ptp_prepare_for_reset(struct ice_pf *pf) -{ - struct ice_ptp *ptp = &pf->ptp; - u8 src_tmr; - - clear_bit(ICE_FLAG_PTP, pf->flags); - - /* Disable timestamping for both Tx and Rx */ - ice_ptp_disable_timestamp_mode(pf); - - kthread_cancel_delayed_work_sync(&ptp->work); - - if (test_bit(ICE_PFR_REQ, pf->state)) - return; - - ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); - - /* Disable periodic outputs */ - ice_ptp_disable_all_clkout(pf); - - src_tmr = ice_get_ptp_src_clock_index(&pf->hw); - - /* Disable source clock */ - wr32(&pf->hw, GLTSYN_ENA(src_tmr), (u32)~GLTSYN_ENA_TSYN_ENA_M); - - /* Acquire PHC and system timer to restore after reset */ - ptp->reset_time = ktime_get_real_ns(); -} - -/** * ice_ptp_init_owner - Initialize PTP_1588_CLOCK device * @pf: Board private structure * @@ -2967,7 +3002,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf) { struct ice_hw *hw = &pf->hw; struct timespec64 ts; - int err, itr = 1; + int err; err = ice_ptp_init_phc(hw); if (err) { @@ -3002,7 +3037,7 @@ static int ice_ptp_init_owner(struct ice_pf *pf) if (!ice_is_e810(hw)) { /* Enable quad interrupts */ - err = ice_ptp_tx_ena_intr(pf, true, itr); + err = ice_ptp_cfg_phy_interrupt(pf, true, 1); if (err) goto err_exit; } @@ -3195,6 +3230,8 @@ void ice_ptp_init(struct ice_pf *pf) struct ice_hw *hw = &pf->hw; int err; + ptp->state = ICE_PTP_INITIALIZING; + ice_ptp_init_phy_model(hw); ice_ptp_init_tx_interrupt_mode(pf); @@ -3219,12 +3256,13 @@ void ice_ptp_init(struct ice_pf *pf) /* Configure initial Tx interrupt settings */ ice_ptp_cfg_tx_interrupt(pf); - set_bit(ICE_FLAG_PTP, pf->flags); - err = ice_ptp_init_work(pf, ptp); + err = ice_ptp_create_auxbus_device(pf); if (err) goto err; - err = ice_ptp_create_auxbus_device(pf); + ptp->state = ICE_PTP_READY; + + err = ice_ptp_init_work(pf, ptp); if (err) goto err; @@ -3237,7 +3275,7 @@ err: ptp_clock_unregister(ptp->clock); pf->ptp.clock = NULL; } - clear_bit(ICE_FLAG_PTP, pf->flags); + ptp->state = ICE_PTP_ERROR; dev_err(ice_pf_to_dev(pf), "PTP failed %d\n", err); } @@ -3250,9 +3288,11 @@ err: */ void ice_ptp_release(struct ice_pf *pf) { - if (!test_bit(ICE_FLAG_PTP, pf->flags)) + if (pf->ptp.state != ICE_PTP_READY) return; + pf->ptp.state = ICE_PTP_UNINIT; + /* Disable timestamping for both Tx and Rx */ ice_ptp_disable_timestamp_mode(pf); @@ -3260,8 +3300,6 @@ void ice_ptp_release(struct ice_pf *pf) ice_ptp_release_tx_tracker(pf, &pf->ptp.port.tx); - clear_bit(ICE_FLAG_PTP, pf->flags); - kthread_cancel_delayed_work_sync(&pf->ptp.work); ice_ptp_port_phy_stop(&pf->ptp.port); @@ -3271,6 +3309,9 @@ void ice_ptp_release(struct ice_pf *pf) pf->ptp.kworker = NULL; } + if (ice_pf_src_tmr_owned(pf)) + ice_ptp_unregister_auxbus_driver(pf); + if (!pf->ptp.clock) return; @@ -3280,7 +3321,5 @@ void ice_ptp_release(struct ice_pf *pf) ptp_clock_unregister(pf->ptp.clock); pf->ptp.clock = NULL; - ice_ptp_unregister_auxbus_driver(pf); - dev_info(ice_pf_to_dev(pf), "Removed PTP clock\n"); } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 087dd32d8762..3af20025043a 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -100,7 +100,7 @@ struct ice_perout_channel { * the last timestamp we read for a given index. If the current timestamp * value is the same as the cached value, we assume a new timestamp hasn't * been captured. This avoids reporting stale timestamps to the stack. This is - * only done if the verify_cached flag is set in ice_ptp_tx structure. + * only done if the has_ready_bitmap flag is not set in ice_ptp_tx structure. */ struct ice_tx_tstamp { struct sk_buff *skb; @@ -130,7 +130,9 @@ enum ice_tx_tstamp_work { * @init: if true, the tracker is initialized; * @calibrating: if true, the PHY is calibrating the Tx offset. During this * window, timestamps are temporarily disabled. - * @verify_cached: if true, verify new timestamp differs from last read value + * @has_ready_bitmap: if true, the hardware has a valid Tx timestamp ready + * bitmap register. If false, fall back to verifying new + * timestamp values against previously cached copy. * @last_ll_ts_idx_read: index of the last LL TS read by the FW */ struct ice_ptp_tx { @@ -143,7 +145,7 @@ struct ice_ptp_tx { u8 len; u8 init : 1; u8 calibrating : 1; - u8 verify_cached : 1; + u8 has_ready_bitmap : 1; s8 last_ll_ts_idx_read; }; @@ -203,8 +205,17 @@ struct ice_ptp_port_owner { #define GLTSYN_TGT_H_IDX_MAX 4 +enum ice_ptp_state { + ICE_PTP_UNINIT = 0, + ICE_PTP_INITIALIZING, + ICE_PTP_READY, + ICE_PTP_RESETTING, + ICE_PTP_ERROR, +}; + /** * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK + * @state: current state of PTP state machine * @tx_interrupt_mode: the TX interrupt mode for the PTP clock * @port: data for the PHY port initialization procedure * @ports_owner: data for the auxiliary driver owner @@ -227,6 +238,7 @@ struct ice_ptp_port_owner { * @late_cached_phc_updates: number of times cached PHC update is late */ struct ice_ptp { + enum ice_ptp_state state; enum ice_ptp_tx_interrupt tx_interrupt_mode; struct ice_ptp_port port; struct ice_ptp_port_owner ports_owner; @@ -304,8 +316,9 @@ enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf); u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, const struct ice_pkt_ctx *pkt_ctx); -void ice_ptp_reset(struct ice_pf *pf); -void ice_ptp_prepare_for_reset(struct ice_pf *pf); +void ice_ptp_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type); +void ice_ptp_prepare_for_reset(struct ice_pf *pf, + enum ice_reset_req reset_type); void ice_ptp_init(struct ice_pf *pf); void ice_ptp_release(struct ice_pf *pf); void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup); @@ -345,8 +358,15 @@ ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc, return 0; } -static inline void ice_ptp_reset(struct ice_pf *pf) { } -static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf) { } +static inline void ice_ptp_rebuild(struct ice_pf *pf, + enum ice_reset_req reset_type) +{ +} + +static inline void ice_ptp_prepare_for_reset(struct ice_pf *pf, + enum ice_reset_req reset_type) +{ +} static inline void ice_ptp_init(struct ice_pf *pf) { } static inline void ice_ptp_release(struct ice_pf *pf) { } static inline void ice_ptp_link_change(struct ice_pf *pf, u8 port, bool linkup) diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index b66199c9bb3a..b87b23d2151c 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -3027,7 +3027,7 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) return ret; } -static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; @@ -3038,10 +3038,10 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) (hw->phy.media_type != e1000_media_type_copper)) return -EOPNOTSUPP; - edata->supported = (SUPPORTED_1000baseT_Full | - SUPPORTED_100baseT_Full); + edata->supported_u32 = (SUPPORTED_1000baseT_Full | + SUPPORTED_100baseT_Full); if (!hw->dev_spec._82575.eee_disable) - edata->advertised = + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); /* The IPCNFG and EEER registers are not supported on I354. */ @@ -3068,7 +3068,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); break; case e1000_i354: case e1000_i210: @@ -3079,7 +3079,7 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) if (ret_val) return -ENODATA; - edata->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(phy_data); + edata->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(phy_data); break; default: @@ -3099,18 +3099,18 @@ static int igb_get_eee(struct net_device *netdev, struct ethtool_eee *edata) edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised &= ~edata->advertised; + edata->advertised_u32 &= ~edata->advertised_u32; } return 0; } static int igb_set_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; bool adv1g_eee = true, adv100m_eee = true; s32 ret_val; @@ -3118,7 +3118,7 @@ static int igb_set_eee(struct net_device *netdev, (hw->phy.media_type != e1000_media_type_copper)) return -EOPNOTSUPP; - memset(&eee_curr, 0, sizeof(struct ethtool_eee)); + memset(&eee_curr, 0, sizeof(struct ethtool_keee)); ret_val = igb_get_eee(netdev, &eee_curr); if (ret_val) @@ -3138,14 +3138,14 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - if (!edata->advertised || (edata->advertised & + if (!edata->advertised_u32 || (edata->advertised_u32 & ~(ADVERTISE_100_FULL | ADVERTISE_1000_FULL))) { dev_err(&adapter->pdev->dev, "EEE Advertisement supports only 100Tx and/or 100T full duplex\n"); return -EINVAL; } - adv100m_eee = !!(edata->advertised & ADVERTISE_100_FULL); - adv1g_eee = !!(edata->advertised & ADVERTISE_1000_FULL); + adv100m_eee = !!(edata->advertised_u32 & ADVERTISE_100_FULL); + adv1g_eee = !!(edata->advertised_u32 & ADVERTISE_1000_FULL); } else if (!edata->eee_enabled) { dev_err(&adapter->pdev->dev, @@ -3153,7 +3153,7 @@ static int igb_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); if (hw->dev_spec._82575.eee_disable != !edata->eee_enabled) { hw->dev_spec._82575.eee_disable = !edata->eee_enabled; adapter->flags |= IGB_FLAG_EEE; diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h index 45430e246e9c..75f7c5ba65e0 100644 --- a/drivers/net/ethernet/intel/igc/igc.h +++ b/drivers/net/ethernet/intel/igc/igc.h @@ -168,7 +168,7 @@ struct igc_ring { struct igc_adapter { struct net_device *netdev; - struct ethtool_eee eee; + struct ethtool_keee eee; u16 eee_advert; unsigned long state; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index b95d2c86e803..7f844e967421 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -1623,18 +1623,18 @@ static int igc_ethtool_set_priv_flags(struct net_device *netdev, u32 priv_flags) } static int igc_ethtool_get_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; u32 eeer; if (hw->dev_spec._base.eee_enable) - edata->advertised = + edata->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(adapter->eee_advert); *edata = adapter->eee; - edata->supported = SUPPORTED_Autoneg; + edata->supported_u32 = SUPPORTED_Autoneg; eeer = rd32(IGC_EEER); @@ -1647,8 +1647,8 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = hw->dev_spec._base.eee_enable; - edata->advertised = SUPPORTED_Autoneg; - edata->lp_advertised = SUPPORTED_Autoneg; + edata->advertised_u32 = SUPPORTED_Autoneg; + edata->lp_advertised_u32 = SUPPORTED_Autoneg; /* Report correct negotiated EEE status for devices that * wrongly report EEE at half-duplex @@ -1657,21 +1657,21 @@ static int igc_ethtool_get_eee(struct net_device *netdev, edata->eee_enabled = false; edata->eee_active = false; edata->tx_lpi_enabled = false; - edata->advertised &= ~edata->advertised; + edata->advertised_u32 &= ~edata->advertised_u32; } return 0; } static int igc_ethtool_set_eee(struct net_device *netdev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct igc_adapter *adapter = netdev_priv(netdev); struct igc_hw *hw = &adapter->hw; - struct ethtool_eee eee_curr; + struct ethtool_keee eee_curr; s32 ret_val; - memset(&eee_curr, 0, sizeof(struct ethtool_eee)); + memset(&eee_curr, 0, sizeof(struct ethtool_keee)); ret_val = igc_ethtool_get_eee(netdev, &eee_curr); if (ret_val) { @@ -1699,7 +1699,7 @@ static int igc_ethtool_set_eee(struct net_device *netdev, return -EINVAL; } - adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised); + adapter->eee_advert = ethtool_adv_to_mmd_eee_adv_t(edata->advertised_u32); if (hw->dev_spec._base.eee_enable != edata->eee_enabled) { hw->dev_spec._base.eee_enable = edata->eee_enabled; adapter->flags |= IGC_FLAG_EEE; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 9a63457712c7..ca69a8221793 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -3425,7 +3425,7 @@ static const struct { }; static int -ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata) +ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_keee *edata) { u32 info[FW_PHY_ACT_DATA_COUNT] = { 0 }; struct ixgbe_hw *hw = &adapter->hw; @@ -3436,33 +3436,33 @@ ixgbe_get_eee_fw(struct ixgbe_adapter *adapter, struct ethtool_eee *edata) if (rc) return rc; - edata->lp_advertised = 0; + edata->lp_advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) { if (info[0] & ixgbe_lp_map[i].lp_advertised) - edata->lp_advertised |= ixgbe_lp_map[i].mac_speed; + edata->lp_advertised_u32 |= ixgbe_lp_map[i].mac_speed; } - edata->supported = 0; + edata->supported_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed) - edata->supported |= ixgbe_ls_map[i].supported; + edata->supported_u32 |= ixgbe_ls_map[i].supported; } - edata->advertised = 0; + edata->advertised_u32 = 0; for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed) - edata->advertised |= ixgbe_ls_map[i].supported; + edata->advertised_u32 |= ixgbe_ls_map[i].supported; } - edata->eee_enabled = !!edata->advertised; + edata->eee_enabled = !!edata->advertised_u32; edata->tx_lpi_enabled = edata->eee_enabled; - if (edata->advertised & edata->lp_advertised) + if (edata->advertised_u32 & edata->lp_advertised_u32) edata->eee_active = true; return 0; } -static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; @@ -3476,17 +3476,17 @@ static int ixgbe_get_eee(struct net_device *netdev, struct ethtool_eee *edata) return -EOPNOTSUPP; } -static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata) +static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_keee *edata) { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; - struct ethtool_eee eee_data; + struct ethtool_keee eee_data; s32 ret_val; if (!(adapter->flags2 & IXGBE_FLAG2_EEE_CAPABLE)) return -EOPNOTSUPP; - memset(&eee_data, 0, sizeof(struct ethtool_eee)); + memset(&eee_data, 0, sizeof(struct ethtool_keee)); ret_val = ixgbe_get_eee(netdev, &eee_data); if (ret_val) @@ -3504,7 +3504,7 @@ static int ixgbe_set_eee(struct net_device *netdev, struct ethtool_eee *edata) return -EINVAL; } - if (eee_data.advertised != edata->advertised) { + if (eee_data.advertised_u32 != edata->advertised_u32) { e_err(drv, "Setting EEE advertised speeds is not supported\n"); return -EINVAL; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index a641b3534ca3..40a5f1431e4e 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -5097,7 +5097,7 @@ static int mvneta_ethtool_set_wol(struct net_device *dev, } static int mvneta_ethtool_get_eee(struct net_device *dev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct mvneta_port *pp = netdev_priv(dev); u32 lpi_ctl0; @@ -5113,7 +5113,7 @@ static int mvneta_ethtool_get_eee(struct net_device *dev, } static int mvneta_ethtool_set_eee(struct net_device *dev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct mvneta_port *pp = netdev_priv(dev); u32 lpi_ctl0; diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h index edeb0f737312..bb8d60e7bab1 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h @@ -1114,6 +1114,7 @@ struct nix_rss_flowkey_cfg { #define NIX_FLOW_KEY_TYPE_INNR_UDP BIT(15) #define NIX_FLOW_KEY_TYPE_INNR_SCTP BIT(16) #define NIX_FLOW_KEY_TYPE_INNR_ETH_DMAC BIT(17) +#define NIX_FLOW_KEY_TYPE_CUSTOM0 BIT(19) #define NIX_FLOW_KEY_TYPE_VLAN BIT(20) #define NIX_FLOW_KEY_TYPE_IPV4_PROTO BIT(21) #define NIX_FLOW_KEY_TYPE_AH BIT(22) diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/npc.h index b0b4dea548e1..3e6de9d7dde3 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc.h @@ -85,8 +85,7 @@ enum npc_kpu_lc_ltype { enum npc_kpu_ld_ltype { NPC_LT_LD_TCP = 1, NPC_LT_LD_UDP, - NPC_LT_LD_ICMP, - NPC_LT_LD_SCTP, + NPC_LT_LD_SCTP = 4, NPC_LT_LD_ICMP6, NPC_LT_LD_CUSTOM0, NPC_LT_LD_CUSTOM1, @@ -97,6 +96,7 @@ enum npc_kpu_ld_ltype { NPC_LT_LD_NSH, NPC_LT_LD_TU_MPLS_IN_NSH, NPC_LT_LD_TU_MPLS_IN_IP, + NPC_LT_LD_ICMP, }; enum npc_kpu_le_ltype { @@ -140,14 +140,14 @@ enum npc_kpu_lg_ltype { enum npc_kpu_lh_ltype { NPC_LT_LH_TU_TCP = 1, NPC_LT_LH_TU_UDP, - NPC_LT_LH_TU_ICMP, - NPC_LT_LH_TU_SCTP, + NPC_LT_LH_TU_SCTP = 4, NPC_LT_LH_TU_ICMP6, + NPC_LT_LH_CUSTOM0, + NPC_LT_LH_CUSTOM1, NPC_LT_LH_TU_IGMP = 8, NPC_LT_LH_TU_ESP, NPC_LT_LH_TU_AH, - NPC_LT_LH_CUSTOM0 = 0xE, - NPC_LT_LH_CUSTOM1 = 0xF, + NPC_LT_LH_TU_ICMP = 0xF, }; /* NPC port kind defines how the incoming or outgoing packets @@ -155,10 +155,11 @@ enum npc_kpu_lh_ltype { * Software assigns pkind for each incoming port such as CGX * Ethernet interfaces, LBK interfaces, etc. */ -#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_CUSTOM_PRE_L2_PKIND +#define NPC_UNRESERVED_PKIND_COUNT NPC_RX_CPT_HDR_PTP_PKIND enum npc_pkind_type { NPC_RX_LBK_PKIND = 0ULL, + NPC_RX_CPT_HDR_PTP_PKIND = 54ULL, NPC_RX_CUSTOM_PRE_L2_PKIND = 55ULL, NPC_RX_VLAN_EXDSA_PKIND = 56ULL, NPC_RX_CHLEN24B_PKIND = 57ULL, diff --git a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h index a820bad3abb2..41de72c8607f 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h +++ b/drivers/net/ethernet/marvell/octeontx2/af/npc_profile.h @@ -35,6 +35,7 @@ #define NPC_ETYPE_NSH 0x894f #define NPC_ETYPE_DSA 0xdada #define NPC_ETYPE_PPPOE 0x8864 +#define NPC_ETYPE_ERSPA 0x88be #define NPC_PPP_IP 0x0021 #define NPC_PPP_IP6 0x0057 @@ -59,6 +60,9 @@ #define NPC_IPNH_MPLS 137 #define NPC_IPNH_HOSTID 139 #define NPC_IPNH_SHIM6 140 +#define NPC_IPNH_CUSTOM 253 + +#define NPC_IP6_ROUTE_TYPE 4 #define NPC_UDP_PORT_PTP_E 319 #define NPC_UDP_PORT_PTP_G 320 @@ -187,6 +191,7 @@ enum npc_kpu_parser_state { NPC_S_KPU2_EXDSA, NPC_S_KPU2_CPT_CTAG, NPC_S_KPU2_CPT_QINQ, + NPC_S_KPU2_MT, NPC_S_KPU3_CTAG, NPC_S_KPU3_STAG, NPC_S_KPU3_QINQ, @@ -231,6 +236,7 @@ enum npc_kpu_parser_state { NPC_S_KPU8_ICMP6, NPC_S_KPU8_GRE, NPC_S_KPU8_AH, + NPC_S_KPU8_CUSTOM, NPC_S_KPU9_TU_MPLS_IN_GRE, NPC_S_KPU9_TU_MPLS_IN_NSH, NPC_S_KPU9_TU_MPLS_IN_IP, @@ -242,6 +248,7 @@ enum npc_kpu_parser_state { NPC_S_KPU9_GTPC, NPC_S_KPU9_GTPU, NPC_S_KPU9_ESP, + NPC_S_KPU9_CUSTOM, NPC_S_KPU10_TU_MPLS_IN_VXLANGPE, NPC_S_KPU10_TU_MPLS_PL, NPC_S_KPU10_TU_MPLS, @@ -318,10 +325,10 @@ enum npc_kpu_lc_uflag { NPC_F_LC_U_UNK_PROTO = 0x10, NPC_F_LC_U_IP_FRAG = 0x20, NPC_F_LC_U_IP6_FRAG = 0x40, + NPC_F_LC_L_6TO4 = 0x80, }; enum npc_kpu_lc_lflag { NPC_F_LC_L_IP_IN_IP = 1, - NPC_F_LC_L_6TO4, NPC_F_LC_L_MPLS_IN_IP, NPC_F_LC_L_IP6_TUN_IP6, NPC_F_LC_L_IP6_MPLS_IN_IP, @@ -334,6 +341,8 @@ enum npc_kpu_lc_lflag { NPC_F_LC_L_EXT_MOBILITY, NPC_F_LC_L_EXT_HOSTID, NPC_F_LC_L_EXT_SHIM6, + NPC_F_LC_L_IP6_SRH_SEG_1, + NPC_F_LC_L_IP6_SRH_SEG_2, }; enum npc_kpu_ld_lflag { @@ -970,10 +979,10 @@ static struct npc_kpu_profile_action ikpu_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 12, 16, 20, 0, 0, - NPC_S_KPU1_ETHER, 0, 0, + NPC_S_KPU1_CPT_HDR, 48, 0, NPC_LID_LA, NPC_LT_NA, 0, - 0, 0, 0, 0, + 0, 7, 0, 0, }, { @@ -2786,6 +2795,24 @@ static struct npc_kpu_profile_cam kpu2_cam_entries[] = { 0x0000, }, { + NPC_S_KPU2_MT, 0xff, + NPC_ETYPE_CTAG, + 0xffff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU2_MT, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { NPC_S_NA, 0X00, 0x0000, 0x0000, @@ -4501,6 +4528,24 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { 0xff00, NPC_IP_VER_6, NPC_IP_VER_MASK, + (NPC_IP6_ROUTE_TYPE << 8) | 1, + 0xffff, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + (NPC_IP6_ROUTE_TYPE << 8) | 2, + 0xffff, + }, + { + NPC_S_KPU5_IP6, 0xff, + NPC_IPNH_ROUT << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, 0x0000, 0x0000, }, @@ -4776,6 +4821,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { }, { NPC_S_KPU5_CPT_IP, 0xff, + NPC_IPNH_CUSTOM, + 0x00ff, + NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, + NPC_IP_VER_MASK | NPC_IP_HDR_LEN_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_CPT_IP, 0xff, 0x0000, 0x0000, NPC_IP_VER_4 | NPC_IP_HDR_LEN_5, @@ -4884,6 +4938,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { }, { NPC_S_KPU5_CPT_IP, 0xff, + NPC_IPNH_CUSTOM, + 0x00ff, + NPC_IP_VER_4, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_CPT_IP, 0xff, 0x0000, 0x0000, NPC_IP_VER_4, @@ -5064,6 +5127,15 @@ static struct npc_kpu_profile_cam kpu5_cam_entries[] = { }, { NPC_S_KPU5_CPT_IP6, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + NPC_IP_VER_6, + NPC_IP_VER_MASK, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU5_CPT_IP6, 0xff, 0x0000, 0x0000, NPC_IP_VER_6, @@ -5208,6 +5280,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_FRAG, 0xff, 0x0000, 0x0000, 0x0000, @@ -5325,6 +5406,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_HOP_DEST, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_HOP_DEST, 0xff, 0x0000, 0x0000, 0x0000, @@ -5433,6 +5523,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_ROUT, 0xff, 0x0000, 0x0000, 0x0000, @@ -5532,6 +5631,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_CPT_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_CPT_FRAG, 0xff, 0x0000, 0x0000, 0x0000, @@ -5649,6 +5757,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_CPT_HOP_DEST, 0xff, 0x0000, 0x0000, 0x0000, @@ -5757,6 +5874,15 @@ static struct npc_kpu_profile_cam kpu6_cam_entries[] = { }, { NPC_S_KPU6_IP6_CPT_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU6_IP6_CPT_ROUT, 0xff, 0x0000, 0x0000, 0x0000, @@ -5883,6 +6009,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { }, { NPC_S_KPU7_IP6_ROUT, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_ROUT, 0xff, 0x0000, 0x0000, 0x0000, @@ -5982,6 +6117,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { }, { NPC_S_KPU7_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + NPC_IP6_FRAG_FRAGOFF, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_IP6_FRAG, 0xff, 0x0000, 0x0000, 0x0000, @@ -6081,6 +6225,15 @@ static struct npc_kpu_profile_cam kpu7_cam_entries[] = { }, { NPC_S_KPU7_CPT_IP6_FRAG, 0xff, + NPC_IPNH_CUSTOM << 8, + 0xff00, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU7_CPT_IP6_FRAG, 0xff, 0x0000, 0x0000, 0x0000, @@ -6310,6 +6463,15 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { 0xffff, 0x0000, 0x0000, + 0x0009, + 0xffff, + }, + { + NPC_S_KPU8_UDP, 0xff, + NPC_UDP_PORT_ESP, + 0xffff, + 0x0000, + 0x0000, 0x0000, 0x0000, }, @@ -6756,6 +6918,78 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { }, { NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + 0x0000, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_KEY, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_KEY | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, + NPC_ETYPE_ERSPA, + 0xffff, + NPC_GRE_F_CSUM | NPC_GRE_F_KEY | NPC_GRE_F_SEQ, + 0xffff, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU8_GRE, 0xff, 0x0000, 0xffff, NPC_GRE_F_ROUTE, @@ -6836,6 +7070,15 @@ static struct npc_kpu_profile_cam kpu8_cam_entries[] = { 0x0000, }, { + NPC_S_KPU8_CUSTOM, 0xff, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { NPC_S_NA, 0X00, 0x0000, 0x0000, @@ -7304,6 +7547,24 @@ static struct npc_kpu_profile_cam kpu9_cam_entries[] = { 0x0000, }, { + NPC_S_KPU9_CUSTOM, 0xff, + 0x4000, + 0xf000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { + NPC_S_KPU9_CUSTOM, 0xff, + 0x6000, + 0xf000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + }, + { NPC_S_NA, 0X00, 0x0000, 0x0000, @@ -8384,7 +8645,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LA, NPC_LT_LA_ETHER, 0, @@ -8536,7 +8797,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 22, 1, NPC_LID_LA, NPC_LT_LA_IH_NIX_ETHER, NPC_F_LA_U_HAS_IH_NIX, @@ -8693,7 +8954,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 30, 1, NPC_LID_LA, NPC_LT_LA_HIGIG2_ETHER, NPC_F_LA_U_HAS_HIGIG2, @@ -8818,7 +9079,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 38, 1, NPC_LID_LA, NPC_LT_LA_IH_NIX_HIGIG2_ETHER, NPC_F_LA_U_HAS_IH_NIX | NPC_F_LA_U_HAS_HIGIG2, @@ -8947,7 +9208,7 @@ static struct npc_kpu_profile_action kpu1_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 3, 0, + 6, 0, 42, 3, 0, NPC_S_KPU5_IP6, 14, 0, NPC_LID_LA, NPC_LT_NA, 0, @@ -9124,7 +9385,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 6, 1, NPC_LID_LB, NPC_LT_LB_CTAG, 0, @@ -9204,7 +9465,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, @@ -9213,7 +9474,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, + NPC_S_NA, 6, 1, NPC_LID_LB, NPC_LT_LB_CTAG, NPC_F_LB_U_UNK_ETYPE, 0, 0, 0, 0, @@ -9228,7 +9489,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, @@ -9324,7 +9585,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 24, 1, NPC_LID_LB, NPC_LT_LB_BTAG, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG, @@ -9428,7 +9689,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_CTAG, @@ -9532,7 +9793,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_ETAG, 0, @@ -9628,7 +9889,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 28, 1, NPC_LID_LB, NPC_LT_LB_ETAG, NPC_F_LB_U_MORE_TAG | NPC_F_LB_L_WITH_ITAG, @@ -9684,7 +9945,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -9757,7 +10018,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, + NPC_S_NA, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, NPC_F_LB_U_UNK_ETYPE, 0, 0, 0, 0, @@ -9772,7 +10033,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 18, 1, NPC_LID_LB, NPC_LT_LB_EDSA, NPC_F_LB_L_EDSA, @@ -9836,7 +10097,7 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 2, 0, + 6, 0, 42, 2, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_EXDSA, NPC_F_LB_L_EXDSA, @@ -9923,6 +10184,22 @@ static struct npc_kpu_profile_action kpu2_action_entries[] = { 0, 0, 0, 0, }, { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 4, 0, 0, 0, 0, + NPC_S_KPU3_CTAG, 0, 1, + NPC_LID_LB, NPC_LT_LB_CTAG, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU3_CTAG_C, 0, 0, + NPC_LID_LB, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { NPC_ERRLEV_LB, NPC_EC_L2_K3, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, @@ -9949,7 +10226,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 6, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10029,7 +10306,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10101,7 +10378,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10165,7 +10442,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10237,7 +10514,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 0, NPC_LID_LB, NPC_LT_NA, 0, @@ -10310,80 +10587,80 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 6, 1, 0, - NPC_S_KPU5_IP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_IP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, - NPC_S_KPU5_IP6, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + 6, 0, 42, 1, 0, + NPC_S_KPU5_IP6, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_ARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_ARP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_RARP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_RARP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_PTP, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_PTP, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 1, 0, - NPC_S_KPU5_FCOE, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU5_FCOE, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, 0, 0, - NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_MPLS, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 6, 10, 0, 0, - NPC_S_KPU4_MPLS, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_MPLS, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, 2, 0, 0, 0, 0, - NPC_S_KPU4_NSH, 4, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_KPU4_NSH, 2, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_LB, NPC_EC_L2_K3_ETYPE_UNK, 0, 0, 0, 0, 1, - NPC_S_NA, 0, 1, - NPC_LID_LB, NPC_LT_LB_CTAG, + NPC_S_NA, 0, 0, + NPC_LID_LB, NPC_LT_NA, 0, 0, 0, 0, 0, }, @@ -10397,7 +10674,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10469,7 +10746,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10533,7 +10810,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 8, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10605,7 +10882,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 4, 1, NPC_LID_LB, NPC_LT_LB_STAG_QINQ, 0, @@ -10685,7 +10962,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_DSA, NPC_F_LB_L_DSA, @@ -10733,7 +11010,7 @@ static struct npc_kpu_profile_action kpu3_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 1, 0, + 6, 0, 42, 1, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_DSA_VLAN, NPC_F_LB_L_DSA_VLAN, @@ -10894,7 +11171,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 6, 1, NPC_LID_LB, NPC_LT_LB_FDSA, NPC_F_LB_L_FDSA, @@ -10942,7 +11219,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_FDSA, NPC_F_LB_L_FDSA, @@ -10990,7 +11267,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 14, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, @@ -11014,7 +11291,7 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, + 6, 0, 42, 0, 0, NPC_S_KPU5_IP6, 2, 0, NPC_LID_LC, NPC_LT_NA, 0, @@ -11063,15 +11340,15 @@ static struct npc_kpu_profile_action kpu4_action_entries[] = { { NPC_ERRLEV_RE, NPC_EC_NOERR, 8, 0, 6, 0, 0, - NPC_S_KPU5_IP, 10, 0, + NPC_S_KPU5_IP, 10, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, 0, 0, 0, 0, }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 6, 0, 0, 0, 0, - NPC_S_KPU5_IP6, 10, 0, + 6, 0, 42, 0, 0, + NPC_S_KPU5_IP6, 10, 1, NPC_LID_LB, NPC_LT_LB_PPPOE, 0, 0, 0, 0, 0, @@ -11119,7 +11396,7 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 2, 0, 0, 2, 0, + 2, 0, 4, 2, 0, NPC_S_KPU8_UDP, 20, 1, NPC_LID_LC, NPC_LT_LC_IP, 0, @@ -11223,7 +11500,7 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, - 2, 8, 10, 2, 0, + 2, 8, 4, 2, 0, NPC_S_KPU8_UDP, 0, 1, NPC_LID_LC, NPC_LT_LC_IP_OPT, 0, @@ -11450,6 +11727,22 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { 0, 0, 0, 0, 0, NPC_S_KPU6_IP6_ROUT, 40, 1, NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_IP6_SRH_SEG_1, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_ROUT, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, + NPC_F_LC_L_IP6_SRH_SEG_2, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU6_IP6_ROUT, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6_EXT, NPC_F_LC_L_EXT_ROUT, 0, 0, 0, 0, }, @@ -11695,6 +11988,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 20, 1, + NPC_LID_LC, NPC_LT_LC_IP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 1, NPC_LID_LC, NPC_LT_LC_IP, @@ -11791,6 +12092,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 0, 1, + NPC_LID_LC, NPC_LT_LC_IP_OPT, + 0, + 0, 0xf, 0, 2, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 1, NPC_LID_LC, NPC_LT_LC_IP_OPT, @@ -11951,6 +12260,14 @@ static struct npc_kpu_profile_action kpu5_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 2, 0, + NPC_S_KPU8_CUSTOM, 40, 1, + NPC_LID_LC, NPC_LT_LC_IP6, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 1, NPC_LID_LC, NPC_LT_LC_IP6, @@ -12080,6 +12397,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12184,6 +12509,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12280,6 +12613,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12368,6 +12709,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12472,6 +12821,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12568,6 +12925,14 @@ static struct npc_kpu_profile_action kpu6_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 1, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12681,6 +13046,14 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 1, 0xff, 0, 3, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12769,6 +13142,14 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -12857,6 +13238,14 @@ static struct npc_kpu_profile_action kpu7_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU8_CUSTOM, 8, 0, + NPC_LID_LC, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, NPC_LID_LC, NPC_LT_NA, @@ -13058,6 +13447,14 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 0, 0, 0, 0, 1, + NPC_S_NA, 8, 1, + NPC_LID_LD, NPC_LT_LD_UDP, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 0, NPC_S_KPU9_ESP, 8, 1, NPC_LID_LD, NPC_LT_LD_UDP, @@ -13458,6 +13855,70 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { }, { NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 12, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 16, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 20, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_KEY_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 12, 16, 20, 2, 0, + NPC_S_KPU11_TU_ETHER, 24, 1, + NPC_LID_LD, NPC_LT_LD_GRE, + NPC_F_LD_L_GRE_HAS_CSUM_KEY_SEQ, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, 0, 0, 0, 0, 1, NPC_S_NA, 0, 1, NPC_LID_LD, NPC_LT_LD_GRE, @@ -13529,6 +13990,14 @@ static struct npc_kpu_profile_action kpu8_action_entries[] = { 0, 0, 0, 0, }, { + NPC_ERRLEV_LD, NPC_EC_NOERR, + 0, 0, 0, 0, 0, + NPC_S_KPU9_CUSTOM, 0, 1, + NPC_LID_LF, NPC_LT_LF_CUSTOM0, + 0, + 0, 0xff, 0, 0, + }, + { NPC_ERRLEV_LD, NPC_EC_UNK, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, @@ -13946,6 +14415,22 @@ static struct npc_kpu_profile_action kpu9_action_entries[] = { 0, 0, 0, 0, }, { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 8, 0, 6, 2, 0, + NPC_S_KPU12_TU_IP, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { + NPC_ERRLEV_RE, NPC_EC_NOERR, + 6, 0, 0, 2, 0, + NPC_S_KPU12_TU_IP6, 0, 0, + NPC_LID_LE, NPC_LT_NA, + 0, + 0, 0, 0, 0, + }, + { NPC_ERRLEV_LE, NPC_EC_UNK, 0, 0, 0, 0, 1, NPC_S_NA, 0, 0, @@ -15105,7 +15590,9 @@ static struct npc_lt_def_cfg npc_lt_defaults = { }, .rx_et = { { - .lid = NPC_LID_LB, + .offset = -2, + .valid = 1, + .lid = NPC_LID_LC, .ltype_match = NPC_LT_NA, .ltype_mask = 0x0, }, @@ -15139,6 +15626,12 @@ static struct npc_mcam_kex npc_mkex_default = { /* Ethertype: 2 bytes, KW0[55:40] */ KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x5), }, + [NPC_LT_LA_CPT_HDR] = { + /* DMAC: 6 bytes, KW1[55:8] */ + KEX_LD_CFG(0x05, 0x0, 0x1, 0x0, NPC_KEXOF_DMAC), + /* Ethertype: 2 bytes, KW0[55:40] */ + KEX_LD_CFG(0x01, 0xc, 0x1, 0x0, 0x5), + }, /* Layer A: HiGig2: */ [NPC_LT_LA_HIGIG2_ETHER] = { /* Classification: 2 bytes, KW1[23:8] */ diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c index 66203a90f052..febd00c63bf6 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c @@ -4039,6 +4039,13 @@ static int set_flowkey_fields(struct nix_rx_flowkey_alg *alg, u32 flow_cfg) field->ltype_match = NPC_LT_LE_GTPU; field->ltype_mask = 0xF; break; + case NIX_FLOW_KEY_TYPE_CUSTOM0: + field->lid = NPC_LID_LC; + field->hdr_offset = 6; + field->bytesm1 = 1; /* 2 Bytes*/ + field->ltype_match = NPC_LT_LC_CUSTOM0; + field->ltype_mask = 0xF; + break; case NIX_FLOW_KEY_TYPE_VLAN: field->lid = NPC_LID_LB; field->hdr_offset = 2; /* Skip TPID (2-bytes) */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c index 18fed2b34fb1..4ad3d2d3d4c8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/dpll.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/dpll.c @@ -41,6 +41,7 @@ struct mlx5_dpll_synce_status { enum mlx5_msees_oper_status oper_status; bool ho_acq; bool oper_freq_measure; + enum mlx5_msees_failure_reason failure_reason; s32 frequency_diff; }; @@ -60,6 +61,7 @@ mlx5_dpll_synce_status_get(struct mlx5_core_dev *mdev, synce_status->oper_status = MLX5_GET(msees_reg, out, oper_status); synce_status->ho_acq = MLX5_GET(msees_reg, out, ho_acq); synce_status->oper_freq_measure = MLX5_GET(msees_reg, out, oper_freq_measure); + synce_status->failure_reason = MLX5_GET(msees_reg, out, failure_reason); synce_status->frequency_diff = MLX5_GET(msees_reg, out, frequency_diff); return 0; } @@ -99,6 +101,26 @@ mlx5_dpll_lock_status_get(struct mlx5_dpll_synce_status *synce_status) } } +static enum dpll_lock_status_error +mlx5_dpll_lock_status_error_get(struct mlx5_dpll_synce_status *synce_status) +{ + switch (synce_status->oper_status) { + case MLX5_MSEES_OPER_STATUS_FAIL_HOLDOVER: + fallthrough; + case MLX5_MSEES_OPER_STATUS_FAIL_FREE_RUNNING: + switch (synce_status->failure_reason) { + case MLX5_MSEES_FAILURE_REASON_PORT_DOWN: + return DPLL_LOCK_STATUS_ERROR_MEDIA_DOWN; + case MLX5_MSEES_FAILURE_REASON_TOO_HIGH_FREQUENCY_DIFF: + return DPLL_LOCK_STATUS_ERROR_FRACTIONAL_FREQUENCY_OFFSET_TOO_HIGH; + default: + return DPLL_LOCK_STATUS_ERROR_UNDEFINED; + } + default: + return DPLL_LOCK_STATUS_ERROR_NONE; + } +} + static enum dpll_pin_state mlx5_dpll_pin_state_get(struct mlx5_dpll_synce_status *synce_status) { @@ -118,10 +140,11 @@ mlx5_dpll_pin_ffo_get(struct mlx5_dpll_synce_status *synce_status, return 0; } -static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, - void *priv, - enum dpll_lock_status *status, - struct netlink_ext_ack *extack) +static int +mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, void *priv, + enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, + struct netlink_ext_ack *extack) { struct mlx5_dpll_synce_status synce_status; struct mlx5_dpll *mdpll = priv; @@ -131,6 +154,7 @@ static int mlx5_dpll_device_lock_status_get(const struct dpll_device *dpll, if (err) return err; *status = mlx5_dpll_lock_status_get(&synce_status); + *status_error = mlx5_dpll_lock_status_error_get(&synce_status); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c index faa63ea9b83e..1915fa41c622 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c @@ -95,7 +95,7 @@ struct mlxsw_afa_set { */ has_trap:1, has_police:1; - unsigned int ref_count; + refcount_t ref_count; struct mlxsw_afa_set *next; /* Pointer to the next set. */ struct mlxsw_afa_set *prev; /* Pointer to the previous set, * note that set may have multiple @@ -120,7 +120,7 @@ struct mlxsw_afa_fwd_entry { struct rhash_head ht_node; struct mlxsw_afa_fwd_entry_ht_key ht_key; u32 kvdl_index; - unsigned int ref_count; + refcount_t ref_count; }; static const struct rhashtable_params mlxsw_afa_fwd_entry_ht_params = { @@ -282,7 +282,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_create(bool is_first) /* Need to initialize the set to pass by default */ mlxsw_afa_set_goto_set(set, MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0); set->ht_key.is_first = is_first; - set->ref_count = 1; + refcount_set(&set->ref_count, 1); return set; } @@ -330,7 +330,7 @@ static void mlxsw_afa_set_unshare(struct mlxsw_afa *mlxsw_afa, static void mlxsw_afa_set_put(struct mlxsw_afa *mlxsw_afa, struct mlxsw_afa_set *set) { - if (--set->ref_count) + if (!refcount_dec_and_test(&set->ref_count)) return; if (set->shared) mlxsw_afa_set_unshare(mlxsw_afa, set); @@ -350,7 +350,7 @@ static struct mlxsw_afa_set *mlxsw_afa_set_get(struct mlxsw_afa *mlxsw_afa, set = rhashtable_lookup_fast(&mlxsw_afa->set_ht, &orig_set->ht_key, mlxsw_afa_set_ht_params); if (set) { - set->ref_count++; + refcount_inc(&set->ref_count); mlxsw_afa_set_put(mlxsw_afa, orig_set); } else { set = orig_set; @@ -564,7 +564,7 @@ mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u16 local_port) if (!fwd_entry) return ERR_PTR(-ENOMEM); fwd_entry->ht_key.local_port = local_port; - fwd_entry->ref_count = 1; + refcount_set(&fwd_entry->ref_count, 1); err = rhashtable_insert_fast(&mlxsw_afa->fwd_entry_ht, &fwd_entry->ht_node, @@ -607,7 +607,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port) fwd_entry = rhashtable_lookup_fast(&mlxsw_afa->fwd_entry_ht, &ht_key, mlxsw_afa_fwd_entry_ht_params); if (fwd_entry) { - fwd_entry->ref_count++; + refcount_inc(&fwd_entry->ref_count); return fwd_entry; } return mlxsw_afa_fwd_entry_create(mlxsw_afa, local_port); @@ -616,7 +616,7 @@ mlxsw_afa_fwd_entry_get(struct mlxsw_afa *mlxsw_afa, u16 local_port) static void mlxsw_afa_fwd_entry_put(struct mlxsw_afa *mlxsw_afa, struct mlxsw_afa_fwd_entry *fwd_entry) { - if (--fwd_entry->ref_count) + if (!refcount_dec_and_test(&fwd_entry->ref_count)) return; mlxsw_afa_fwd_entry_destroy(mlxsw_afa, fwd_entry); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c index 0d5e6f9b466e..947500f8ed71 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.c @@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/errno.h> +#include <linux/refcount.h> #include "item.h" #include "core_acl_flex_keys.h" @@ -107,7 +108,7 @@ EXPORT_SYMBOL(mlxsw_afk_destroy); struct mlxsw_afk_key_info { struct list_head list; - unsigned int ref_count; + refcount_t ref_count; unsigned int blocks_count; int element_to_block[MLXSW_AFK_ELEMENT_MAX]; /* index is element, value * is index inside "blocks" @@ -334,7 +335,7 @@ mlxsw_afk_key_info_create(struct mlxsw_afk *mlxsw_afk, if (err) goto err_picker; list_add(&key_info->list, &mlxsw_afk->key_info_list); - key_info->ref_count = 1; + refcount_set(&key_info->ref_count, 1); return key_info; err_picker: @@ -356,7 +357,7 @@ mlxsw_afk_key_info_get(struct mlxsw_afk *mlxsw_afk, key_info = mlxsw_afk_key_info_find(mlxsw_afk, elusage); if (key_info) { - key_info->ref_count++; + refcount_inc(&key_info->ref_count); return key_info; } return mlxsw_afk_key_info_create(mlxsw_afk, elusage); @@ -365,7 +366,7 @@ EXPORT_SYMBOL(mlxsw_afk_key_info_get); void mlxsw_afk_key_info_put(struct mlxsw_afk_key_info *key_info) { - if (--key_info->ref_count) + if (!refcount_dec_and_test(&key_info->ref_count)) return; mlxsw_afk_key_info_destroy(key_info); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 6b98c3287b49..f0ceb196a6ce 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -708,7 +708,6 @@ static const struct i2c_device_id mlxsw_m_i2c_id[] = { static struct i2c_driver mlxsw_m_i2c_driver = { .driver.name = "mlxsw_minimal", - .class = I2C_CLASS_HWMON, .id_table = mlxsw_m_i2c_id, }; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 5d3413636a62..ecde2086c703 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2695,23 +2695,18 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp) { char sgcr_pl[MLXSW_REG_SGCR_LEN]; - u16 max_lag; int err; if (mlxsw_core_lag_mode(mlxsw_sp->core) != MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW) return 0; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return err; - /* In DDD mode, which we by default use, each LAG entry is 8 PGT * entries. The LAG table address needs to be 8-aligned, but that ought * to be the case, since the LAG table is allocated first. */ err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, &mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); if (err) return err; if (WARN_ON_ONCE(mlxsw_sp->lag_pgt_base % 8)) { @@ -2728,33 +2723,31 @@ static int mlxsw_sp_lag_pgt_init(struct mlxsw_sp *mlxsw_sp) err_mid_alloc_range: mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); return err; } static void mlxsw_sp_lag_pgt_fini(struct mlxsw_sp *mlxsw_sp) { - u16 max_lag; - int err; - if (mlxsw_core_lag_mode(mlxsw_sp->core) != MLXSW_CMD_MBOX_CONFIG_PROFILE_LAG_MODE_SW) return; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return; - mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mlxsw_sp->lag_pgt_base, - max_lag * 8); + mlxsw_sp->max_lag * 8); } #define MLXSW_SP_LAG_SEED_INIT 0xcafecafe +struct mlxsw_sp_lag { + struct net_device *dev; + refcount_t ref_count; + u16 lag_id; +}; + static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; - u16 max_lag; u32 seed; int err; @@ -2773,7 +2766,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); + err = mlxsw_core_max_lag(mlxsw_sp->core, &mlxsw_sp->max_lag); if (err) return err; @@ -2784,7 +2777,7 @@ static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) if (err) return err; - mlxsw_sp->lags = kcalloc(max_lag, sizeof(struct mlxsw_sp_upper), + mlxsw_sp->lags = kcalloc(mlxsw_sp->max_lag, sizeof(struct mlxsw_sp_lag), GFP_KERNEL); if (!mlxsw_sp->lags) { err = -ENOMEM; @@ -4269,19 +4262,48 @@ mlxsw_sp_port_lag_uppers_cleanup(struct mlxsw_sp_port *mlxsw_sp_port, } } -static int mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, u16 lag_id) +static struct mlxsw_sp_lag * +mlxsw_sp_lag_create(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, + struct netlink_ext_ack *extack) { char sldr_pl[MLXSW_REG_SLDR_LEN]; + struct mlxsw_sp_lag *lag; + u16 lag_id; + int i, err; + + for (i = 0; i < mlxsw_sp->max_lag; i++) { + if (!mlxsw_sp->lags[i].dev) + break; + } + + if (i == mlxsw_sp->max_lag) { + NL_SET_ERR_MSG_MOD(extack, + "Exceeded number of supported LAG devices"); + return ERR_PTR(-EBUSY); + } + lag_id = i; mlxsw_reg_sldr_lag_create_pack(sldr_pl, lag_id); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); + if (err) + return ERR_PTR(err); + + lag = &mlxsw_sp->lags[lag_id]; + lag->lag_id = lag_id; + lag->dev = lag_dev; + refcount_set(&lag->ref_count, 1); + + return lag; } -static int mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, u16 lag_id) +static int +mlxsw_sp_lag_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag) { char sldr_pl[MLXSW_REG_SLDR_LEN]; - mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag_id); + lag->dev = NULL; + + mlxsw_reg_sldr_lag_destroy_pack(sldr_pl, lag->lag_id); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sldr), sldr_pl); } @@ -4329,34 +4351,44 @@ static int mlxsw_sp_lag_col_port_disable(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(slcor), slcor_pl); } -static int mlxsw_sp_lag_index_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *lag_dev, - u16 *p_lag_id) +static struct mlxsw_sp_lag * +mlxsw_sp_lag_find(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev) { - struct mlxsw_sp_upper *lag; - int free_lag_id = -1; - u16 max_lag; - int err, i; + int i; - err = mlxsw_core_max_lag(mlxsw_sp->core, &max_lag); - if (err) - return err; + for (i = 0; i < mlxsw_sp->max_lag; i++) { + if (!mlxsw_sp->lags[i].dev) + continue; - for (i = 0; i < max_lag; i++) { - lag = mlxsw_sp_lag_get(mlxsw_sp, i); - if (lag->ref_count) { - if (lag->dev == lag_dev) { - *p_lag_id = i; - return 0; - } - } else if (free_lag_id < 0) { - free_lag_id = i; - } + if (mlxsw_sp->lags[i].dev == lag_dev) + return &mlxsw_sp->lags[i]; } - if (free_lag_id < 0) - return -EBUSY; - *p_lag_id = free_lag_id; - return 0; + + return NULL; +} + +static struct mlxsw_sp_lag * +mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, struct net_device *lag_dev, + struct netlink_ext_ack *extack) +{ + struct mlxsw_sp_lag *lag; + + lag = mlxsw_sp_lag_find(mlxsw_sp, lag_dev); + if (lag) { + refcount_inc(&lag->ref_count); + return lag; + } + + return mlxsw_sp_lag_create(mlxsw_sp, lag_dev, extack); +} + +static void +mlxsw_sp_lag_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lag *lag) +{ + if (!refcount_dec_and_test(&lag->ref_count)) + return; + + mlxsw_sp_lag_destroy(mlxsw_sp, lag); } static bool @@ -4365,12 +4397,6 @@ mlxsw_sp_master_lag_check(struct mlxsw_sp *mlxsw_sp, struct netdev_lag_upper_info *lag_upper_info, struct netlink_ext_ack *extack) { - u16 lag_id; - - if (mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id) != 0) { - NL_SET_ERR_MSG_MOD(extack, "Exceeded number of supported LAG devices"); - return false; - } if (lag_upper_info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { NL_SET_ERR_MSG_MOD(extack, "LAG device using unsupported Tx type"); return false; @@ -4482,22 +4508,16 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, struct netlink_ext_ack *extack) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - struct mlxsw_sp_upper *lag; + struct mlxsw_sp_lag *lag; u16 lag_id; u8 port_index; int err; - err = mlxsw_sp_lag_index_get(mlxsw_sp, lag_dev, &lag_id); - if (err) - return err; - lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); - if (!lag->ref_count) { - err = mlxsw_sp_lag_create(mlxsw_sp, lag_id); - if (err) - return err; - lag->dev = lag_dev; - } + lag = mlxsw_sp_lag_get(mlxsw_sp, lag_dev, extack); + if (IS_ERR(lag)) + return PTR_ERR(lag); + lag_id = lag->lag_id; err = mlxsw_sp_port_lag_index_get(mlxsw_sp, lag_id, &port_index); if (err) return err; @@ -4515,7 +4535,6 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_port->local_port); mlxsw_sp_port->lag_id = lag_id; mlxsw_sp_port->lagged = 1; - lag->ref_count++; err = mlxsw_sp_fid_port_join_lag(mlxsw_sp_port); if (err) @@ -4542,7 +4561,6 @@ err_replay: err_router_join: mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); err_fid_port_join_lag: - lag->ref_count--; mlxsw_sp_port->lagged = 0; mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, mlxsw_sp_port->local_port); @@ -4550,8 +4568,7 @@ err_fid_port_join_lag: err_col_port_add: mlxsw_sp_lag_uppers_bridge_leave(mlxsw_sp_port, lag_dev); err_lag_uppers_bridge_join: - if (!lag->ref_count) - mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); + mlxsw_sp_lag_put(mlxsw_sp, lag); return err; } @@ -4560,12 +4577,11 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 lag_id = mlxsw_sp_port->lag_id; - struct mlxsw_sp_upper *lag; + struct mlxsw_sp_lag *lag; if (!mlxsw_sp_port->lagged) return; - lag = mlxsw_sp_lag_get(mlxsw_sp, lag_id); - WARN_ON(lag->ref_count == 0); + lag = &mlxsw_sp->lags[lag_id]; mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id); @@ -4579,13 +4595,11 @@ static void mlxsw_sp_port_lag_leave(struct mlxsw_sp_port *mlxsw_sp_port, mlxsw_sp_fid_port_leave_lag(mlxsw_sp_port); - if (lag->ref_count == 1) - mlxsw_sp_lag_destroy(mlxsw_sp, lag_id); + mlxsw_sp_lag_put(mlxsw_sp, lag); mlxsw_core_lag_mapping_clear(mlxsw_sp->core, lag_id, mlxsw_sp_port->local_port); mlxsw_sp_port->lagged = 0; - lag->ref_count--; /* Make sure untagged frames are allowed to ingress */ mlxsw_sp_port_pvid_set(mlxsw_sp_port, MLXSW_SP_DEFAULT_VID, diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index a0c9775fa955..898d24232935 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -78,11 +78,6 @@ struct mlxsw_sp_span_entry; enum mlxsw_sp_l3proto; union mlxsw_sp_l3addr; -struct mlxsw_sp_upper { - struct net_device *dev; - unsigned int ref_count; -}; - enum mlxsw_sp_rif_type { MLXSW_SP_RIF_TYPE_SUBPORT, MLXSW_SP_RIF_TYPE_VLAN, @@ -136,6 +131,7 @@ struct mlxsw_sp_span_ops; struct mlxsw_sp_qdisc_state; struct mlxsw_sp_mall_entry; struct mlxsw_sp_pgt; +struct mlxsw_sp_lag; struct mlxsw_sp_port_mapping { u8 module; @@ -164,7 +160,8 @@ struct mlxsw_sp { const struct mlxsw_bus_info *bus_info; unsigned char base_mac[ETH_ALEN]; const unsigned char *mac_mask; - struct mlxsw_sp_upper *lags; + struct mlxsw_sp_lag *lags; + u16 max_lag; struct mlxsw_sp_port_mapping *port_mapping; struct mlxsw_sp_port_mapping_events port_mapping_events; struct rhashtable sample_trigger_ht; @@ -257,12 +254,6 @@ struct mlxsw_sp_fid_core_ops { void (*fini)(struct mlxsw_sp *mlxsw_sp); }; -static inline struct mlxsw_sp_upper * -mlxsw_sp_lag_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id) -{ - return &mlxsw_sp->lags[lag_id]; -} - struct mlxsw_sp_port_pcpu_stats { u64 rx_packets; u64 rx_bytes; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 7c59c8a13584..b01b000bc71c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -9,6 +9,7 @@ #include <linux/rhashtable.h> #include <linux/netdevice.h> #include <linux/mutex.h> +#include <linux/refcount.h> #include <net/net_namespace.h> #include <net/tc_act/tc_vlan.h> @@ -55,7 +56,7 @@ struct mlxsw_sp_acl_ruleset { struct rhash_head ht_node; /* Member of acl HT */ struct mlxsw_sp_acl_ruleset_ht_key ht_key; struct rhashtable rule_ht; - unsigned int ref_count; + refcount_t ref_count; unsigned int min_prio; unsigned int max_prio; unsigned long priv[]; @@ -99,7 +100,7 @@ static bool mlxsw_sp_acl_ruleset_is_singular(const struct mlxsw_sp_acl_ruleset *ruleset) { /* We hold a reference on ruleset ourselves */ - return ruleset->ref_count == 2; + return refcount_read(&ruleset->ref_count) == 2; } int mlxsw_sp_acl_ruleset_bind(struct mlxsw_sp *mlxsw_sp, @@ -176,7 +177,7 @@ mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, ruleset = kzalloc(alloc_size, GFP_KERNEL); if (!ruleset) return ERR_PTR(-ENOMEM); - ruleset->ref_count = 1; + refcount_set(&ruleset->ref_count, 1); ruleset->ht_key.block = block; ruleset->ht_key.chain_index = chain_index; ruleset->ht_key.ops = ops; @@ -222,13 +223,13 @@ static void mlxsw_sp_acl_ruleset_destroy(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_acl_ruleset_ref_inc(struct mlxsw_sp_acl_ruleset *ruleset) { - ruleset->ref_count++; + refcount_inc(&ruleset->ref_count); } static void mlxsw_sp_acl_ruleset_ref_dec(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_ruleset *ruleset) { - if (--ruleset->ref_count) + if (!refcount_dec_and_test(&ruleset->ref_count)) return; mlxsw_sp_acl_ruleset_destroy(mlxsw_sp, ruleset); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 50ea1eff02b2..f20052776b3f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -9,6 +9,7 @@ #include <linux/rhashtable.h> #include <linux/netdevice.h> #include <linux/mutex.h> +#include <linux/refcount.h> #include <net/devlink.h> #include <trace/events/mlxsw.h> @@ -155,7 +156,7 @@ struct mlxsw_sp_acl_tcam_vregion { struct mlxsw_sp_acl_tcam_rehash_ctx ctx; } rehash; struct mlxsw_sp *mlxsw_sp; - unsigned int ref_count; + refcount_t ref_count; }; struct mlxsw_sp_acl_tcam_vchunk; @@ -176,7 +177,7 @@ struct mlxsw_sp_acl_tcam_vchunk { unsigned int priority; /* Priority within the vregion and group */ struct mlxsw_sp_acl_tcam_vgroup *vgroup; struct mlxsw_sp_acl_tcam_vregion *vregion; - unsigned int ref_count; + refcount_t ref_count; }; struct mlxsw_sp_acl_tcam_entry { @@ -769,7 +770,7 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, vregion->tcam = tcam; vregion->mlxsw_sp = mlxsw_sp; vregion->vgroup = vgroup; - vregion->ref_count = 1; + refcount_set(&vregion->ref_count, 1); vregion->key_info = mlxsw_afk_key_info_get(afk, elusage); if (IS_ERR(vregion->key_info)) { @@ -856,7 +857,7 @@ mlxsw_sp_acl_tcam_vregion_get(struct mlxsw_sp *mlxsw_sp, */ return ERR_PTR(-EOPNOTSUPP); } - vregion->ref_count++; + refcount_inc(&vregion->ref_count); return vregion; } @@ -871,7 +872,7 @@ static void mlxsw_sp_acl_tcam_vregion_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion) { - if (--vregion->ref_count) + if (!refcount_dec_and_test(&vregion->ref_count)) return; mlxsw_sp_acl_tcam_vregion_destroy(mlxsw_sp, vregion); } @@ -924,7 +925,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp, INIT_LIST_HEAD(&vchunk->ventry_list); vchunk->priority = priority; vchunk->vgroup = vgroup; - vchunk->ref_count = 1; + refcount_set(&vchunk->ref_count, 1); vregion = mlxsw_sp_acl_tcam_vregion_get(mlxsw_sp, vgroup, priority, elusage); @@ -1008,7 +1009,7 @@ mlxsw_sp_acl_tcam_vchunk_get(struct mlxsw_sp *mlxsw_sp, if (WARN_ON(!mlxsw_afk_key_info_subset(vchunk->vregion->key_info, elusage))) return ERR_PTR(-EINVAL); - vchunk->ref_count++; + refcount_inc(&vchunk->ref_count); return vchunk; } return mlxsw_sp_acl_tcam_vchunk_create(mlxsw_sp, vgroup, @@ -1019,7 +1020,7 @@ static void mlxsw_sp_acl_tcam_vchunk_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vchunk *vchunk) { - if (--vchunk->ref_count) + if (!refcount_dec_and_test(&vchunk->ref_count)) return; mlxsw_sp_acl_tcam_vchunk_destroy(mlxsw_sp, vchunk); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 7164f9e6370f..87617df694ab 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -501,7 +501,7 @@ struct mlxsw_sp_rt6 { struct mlxsw_sp_lpm_tree { u8 id; /* tree ID */ - unsigned int ref_count; + refcount_t ref_count; enum mlxsw_sp_l3proto proto; unsigned long prefix_ref_count[MLXSW_SP_PREFIX_COUNT]; struct mlxsw_sp_prefix_usage prefix_usage; @@ -578,7 +578,7 @@ mlxsw_sp_lpm_tree_find_unused(struct mlxsw_sp *mlxsw_sp) for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { lpm_tree = &mlxsw_sp->router->lpm.trees[i]; - if (lpm_tree->ref_count == 0) + if (refcount_read(&lpm_tree->ref_count) == 0) return lpm_tree; } return NULL; @@ -654,7 +654,7 @@ mlxsw_sp_lpm_tree_create(struct mlxsw_sp *mlxsw_sp, sizeof(lpm_tree->prefix_usage)); memset(&lpm_tree->prefix_ref_count, 0, sizeof(lpm_tree->prefix_ref_count)); - lpm_tree->ref_count = 1; + refcount_set(&lpm_tree->ref_count, 1); return lpm_tree; err_left_struct_set: @@ -678,7 +678,7 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, for (i = 0; i < mlxsw_sp->router->lpm.tree_count; i++) { lpm_tree = &mlxsw_sp->router->lpm.trees[i]; - if (lpm_tree->ref_count != 0 && + if (refcount_read(&lpm_tree->ref_count) && lpm_tree->proto == proto && mlxsw_sp_prefix_usage_eq(&lpm_tree->prefix_usage, prefix_usage)) { @@ -691,14 +691,15 @@ mlxsw_sp_lpm_tree_get(struct mlxsw_sp *mlxsw_sp, static void mlxsw_sp_lpm_tree_hold(struct mlxsw_sp_lpm_tree *lpm_tree) { - lpm_tree->ref_count++; + refcount_inc(&lpm_tree->ref_count); } static void mlxsw_sp_lpm_tree_put(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_lpm_tree *lpm_tree) { - if (--lpm_tree->ref_count == 0) - mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree); + if (!refcount_dec_and_test(&lpm_tree->ref_count)) + return; + mlxsw_sp_lpm_tree_destroy(mlxsw_sp, lpm_tree); } #define MLXSW_SP_LPM_TREE_MIN 1 /* tree 0 is reserved */ diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 6c749c148148..6397ff0dc951 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -61,7 +61,7 @@ struct mlxsw_sp_bridge_port { struct mlxsw_sp_bridge_device *bridge_device; struct list_head list; struct list_head vlans_list; - unsigned int ref_count; + refcount_t ref_count; u8 stp_state; unsigned long flags; bool mrouter; @@ -495,7 +495,7 @@ mlxsw_sp_bridge_port_create(struct mlxsw_sp_bridge_device *bridge_device, BR_MCAST_FLOOD; INIT_LIST_HEAD(&bridge_port->vlans_list); list_add(&bridge_port->list, &bridge_device->ports_list); - bridge_port->ref_count = 1; + refcount_set(&bridge_port->ref_count, 1); err = switchdev_bridge_port_offload(brport_dev, mlxsw_sp_port->dev, NULL, NULL, NULL, false, extack); @@ -531,7 +531,7 @@ mlxsw_sp_bridge_port_get(struct mlxsw_sp_bridge *bridge, bridge_port = mlxsw_sp_bridge_port_find(bridge, brport_dev); if (bridge_port) { - bridge_port->ref_count++; + refcount_inc(&bridge_port->ref_count); return bridge_port; } @@ -558,7 +558,7 @@ static void mlxsw_sp_bridge_port_put(struct mlxsw_sp_bridge *bridge, { struct mlxsw_sp_bridge_device *bridge_device; - if (--bridge_port->ref_count != 0) + if (!refcount_dec_and_test(&bridge_port->ref_count)) return; bridge_device = bridge_port->bridge_device; mlxsw_sp_bridge_port_destroy(bridge_port); diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index 5693784eec5b..2e0fe16a4082 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -513,4 +513,5 @@ int devm_regmap_init_encx24j600(struct device *dev, } EXPORT_SYMBOL_GPL(devm_regmap_init_encx24j600); +MODULE_DESCRIPTION("Microchip ENCX24J600 helpers"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/microchip/lan743x_ethtool.c b/drivers/net/ethernet/microchip/lan743x_ethtool.c index a2b3f4433ca8..8a6ae171e375 100644 --- a/drivers/net/ethernet/microchip/lan743x_ethtool.c +++ b/drivers/net/ethernet/microchip/lan743x_ethtool.c @@ -1055,7 +1055,7 @@ static int lan743x_ethtool_get_ts_info(struct net_device *netdev, } static int lan743x_ethtool_get_eee(struct net_device *netdev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct lan743x_adapter *adapter = netdev_priv(netdev); struct phy_device *phydev = netdev->phydev; @@ -1092,7 +1092,7 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev, } static int lan743x_ethtool_set_eee(struct net_device *netdev, - struct ethtool_eee *eee) + struct ethtool_keee *eee) { struct lan743x_adapter *adapter; struct phy_device *phydev; diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.c b/drivers/net/ethernet/microchip/lan743x_ptp.c index 2f04bc77a118..2801f08bf1c9 100644 --- a/drivers/net/ethernet/microchip/lan743x_ptp.c +++ b/drivers/net/ethernet/microchip/lan743x_ptp.c @@ -1712,13 +1712,13 @@ bool lan743x_ptp_request_tx_timestamp(struct lan743x_adapter *adapter) struct lan743x_ptp *ptp = &adapter->ptp; bool result = false; - spin_lock_bh(&ptp->tx_ts_lock); + spin_lock(&ptp->tx_ts_lock); if (ptp->pending_tx_timestamps < LAN743X_PTP_NUMBER_OF_TX_TIMESTAMPS) { /* request granted */ ptp->pending_tx_timestamps++; result = true; } - spin_unlock_bh(&ptp->tx_ts_lock); + spin_unlock(&ptp->tx_ts_lock); return result; } diff --git a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c index ac525ff1503e..3a01e13bd10b 100644 --- a/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c +++ b/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_debugfs.c @@ -25,6 +25,8 @@ static void lan966x_vcap_is1_port_keys(struct lan966x_port *port, for (int l = 0; l < admin->lookups; ++l) { out->prf(out->dst, "\n Lookup %d: ", l); + val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, l)); + out->prf(out->dst, "\n other: "); switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) { case VCAP_IS1_PS_OTHER_NORMAL: diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index d33b27214539..1332db9a08eb 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -1249,15 +1249,47 @@ void mana_gd_free_res_map(struct gdma_resource *r) r->size = 0; } +static int irq_setup(unsigned int *irqs, unsigned int len, int node) +{ + const struct cpumask *next, *prev = cpu_none_mask; + cpumask_var_t cpus __free(free_cpumask_var); + int cpu, weight; + + if (!alloc_cpumask_var(&cpus, GFP_KERNEL)) + return -ENOMEM; + + rcu_read_lock(); + for_each_numa_hop_mask(next, node) { + weight = cpumask_weight_andnot(next, prev); + while (weight > 0) { + cpumask_andnot(cpus, next, prev); + for_each_cpu(cpu, cpus) { + if (len-- == 0) + goto done; + irq_set_affinity_and_hint(*irqs++, topology_sibling_cpumask(cpu)); + cpumask_andnot(cpus, cpus, topology_sibling_cpumask(cpu)); + --weight; + } + } + prev = next; + } +done: + rcu_read_unlock(); + return 0; +} + static int mana_gd_setup_irqs(struct pci_dev *pdev) { - unsigned int max_queues_per_port = num_online_cpus(); struct gdma_context *gc = pci_get_drvdata(pdev); + unsigned int max_queues_per_port; struct gdma_irq_context *gic; unsigned int max_irqs, cpu; - int nvec, irq; + int start_irq_index = 1; + int nvec, *irqs, irq; int err, i = 0, j; + cpus_read_lock(); + max_queues_per_port = num_online_cpus(); if (max_queues_per_port > MANA_MAX_NUM_QUEUES) max_queues_per_port = MANA_MAX_NUM_QUEUES; @@ -1265,8 +1297,18 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) max_irqs = max_queues_per_port + 1; nvec = pci_alloc_irq_vectors(pdev, 2, max_irqs, PCI_IRQ_MSIX); - if (nvec < 0) + if (nvec < 0) { + cpus_read_unlock(); return nvec; + } + if (nvec <= num_online_cpus()) + start_irq_index = 0; + + irqs = kmalloc_array((nvec - start_irq_index), sizeof(int), GFP_KERNEL); + if (!irqs) { + err = -ENOMEM; + goto free_irq_vector; + } gc->irq_contexts = kcalloc(nvec, sizeof(struct gdma_irq_context), GFP_KERNEL); @@ -1294,17 +1336,41 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev) goto free_irq; } - err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); - if (err) - goto free_irq; - - cpu = cpumask_local_spread(i, gc->numa_node); - irq_set_affinity_and_hint(irq, cpumask_of(cpu)); + if (!i) { + err = request_irq(irq, mana_gd_intr, 0, gic->name, gic); + if (err) + goto free_irq; + + /* If number of IRQ is one extra than number of online CPUs, + * then we need to assign IRQ0 (hwc irq) and IRQ1 to + * same CPU. + * Else we will use different CPUs for IRQ0 and IRQ1. + * Also we are using cpumask_local_spread instead of + * cpumask_first for the node, because the node can be + * mem only. + */ + if (start_irq_index) { + cpu = cpumask_local_spread(i, gc->numa_node); + irq_set_affinity_and_hint(irq, cpumask_of(cpu)); + } else { + irqs[start_irq_index] = irq; + } + } else { + irqs[i - start_irq_index] = irq; + err = request_irq(irqs[i - start_irq_index], mana_gd_intr, 0, + gic->name, gic); + if (err) + goto free_irq; + } } + err = irq_setup(irqs, (nvec - start_irq_index), gc->numa_node); + if (err) + goto free_irq; + gc->max_num_msix = nvec; gc->num_msix_usable = nvec; - + cpus_read_unlock(); return 0; free_irq: @@ -1317,8 +1383,10 @@ free_irq: } kfree(gc->irq_contexts); + kfree(irqs); gc->irq_contexts = NULL; free_irq_vector: + cpus_read_unlock(); pci_free_irq_vectors(pdev); return err; } diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 56ccbd4c37fe..2194f2a7ab27 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -3078,4 +3078,5 @@ void ocelot_deinit_port(struct ocelot *ocelot, int port) } EXPORT_SYMBOL(ocelot_deinit_port); +MODULE_DESCRIPTION("Microsemi Ocelot (VSC7514) Switch driver"); MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c index 0e240b5ab8d4..dfa15619fd78 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_ethtool.c +++ b/drivers/net/ethernet/qlogic/qede/qede_ethtool.c @@ -1776,7 +1776,7 @@ static int qede_get_tunable(struct net_device *dev, return 0; } -static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) +static int qede_get_eee(struct net_device *dev, struct ethtool_keee *edata) { struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; @@ -1790,17 +1790,17 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) } if (current_link.eee.adv_caps & QED_EEE_1G_ADV) - edata->advertised = ADVERTISED_1000baseT_Full; + edata->advertised_u32 = ADVERTISED_1000baseT_Full; if (current_link.eee.adv_caps & QED_EEE_10G_ADV) - edata->advertised |= ADVERTISED_10000baseT_Full; + edata->advertised_u32 |= ADVERTISED_10000baseT_Full; if (current_link.sup_caps & QED_EEE_1G_ADV) - edata->supported = ADVERTISED_1000baseT_Full; + edata->supported_u32 = ADVERTISED_1000baseT_Full; if (current_link.sup_caps & QED_EEE_10G_ADV) - edata->supported |= ADVERTISED_10000baseT_Full; + edata->supported_u32 |= ADVERTISED_10000baseT_Full; if (current_link.eee.lp_adv_caps & QED_EEE_1G_ADV) - edata->lp_advertised = ADVERTISED_1000baseT_Full; + edata->lp_advertised_u32 = ADVERTISED_1000baseT_Full; if (current_link.eee.lp_adv_caps & QED_EEE_10G_ADV) - edata->lp_advertised |= ADVERTISED_10000baseT_Full; + edata->lp_advertised_u32 |= ADVERTISED_10000baseT_Full; edata->tx_lpi_timer = current_link.eee.tx_lpi_timer; edata->eee_enabled = current_link.eee.enable; @@ -1810,7 +1810,7 @@ static int qede_get_eee(struct net_device *dev, struct ethtool_eee *edata) return 0; } -static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata) +static int qede_set_eee(struct net_device *dev, struct ethtool_keee *edata) { struct qede_dev *edev = netdev_priv(dev); struct qed_link_output current_link; @@ -1832,20 +1832,20 @@ static int qede_set_eee(struct net_device *dev, struct ethtool_eee *edata) memset(¶ms, 0, sizeof(params)); params.override_flags |= QED_LINK_OVERRIDE_EEE_CONFIG; - if (!(edata->advertised & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) || - ((edata->advertised & (ADVERTISED_1000baseT_Full | - ADVERTISED_10000baseT_Full)) != - edata->advertised)) { + if (!(edata->advertised_u32 & (ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)) || + ((edata->advertised_u32 & (ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)) != + edata->advertised_u32)) { DP_VERBOSE(edev, QED_MSG_DEBUG, "Invalid advertised capabilities %d\n", - edata->advertised); + edata->advertised_u32); return -EINVAL; } - if (edata->advertised & ADVERTISED_1000baseT_Full) + if (edata->advertised_u32 & ADVERTISED_1000baseT_Full) params.eee.adv_caps = QED_EEE_1G_ADV; - if (edata->advertised & ADVERTISED_10000baseT_Full) + if (edata->advertised_u32 & ADVERTISED_10000baseT_Full) params.eee.adv_caps |= QED_EEE_10G_ADV; params.eee.enable = edata->eee_enabled; params.eee.tx_lpi_enable = edata->tx_lpi_enabled; diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 3270df72541b..4c06f55878de 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -771,5 +771,6 @@ static struct platform_driver emac_platform_driver = { module_platform_driver(emac_platform_driver); +MODULE_DESCRIPTION("Qualcomm EMAC Gigabit Ethernet driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:qcom-emac"); diff --git a/drivers/net/ethernet/qualcomm/qca_7k.c b/drivers/net/ethernet/qualcomm/qca_7k.c index 4292c89bd35c..6263e4cf47fa 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.c +++ b/drivers/net/ethernet/qualcomm/qca_7k.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* - * * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * */ /* This module implements the Qualcomm Atheros SPI protocol for diff --git a/drivers/net/ethernet/qualcomm/qca_7k.h b/drivers/net/ethernet/qualcomm/qca_7k.h index 356de8ec5d48..828ee9c27578 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k.h +++ b/drivers/net/ethernet/qualcomm/qca_7k.h @@ -1,21 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * */ /* Qualcomm Atheros SPI register definition. diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.c b/drivers/net/ethernet/qualcomm/qca_7k_common.c index 6b511f05df61..5302da587620 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.c +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Atheros ethernet framing. Every Ethernet frame is surrounded @@ -162,5 +149,5 @@ EXPORT_SYMBOL_GPL(qcafrm_fsm_decode); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 common"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/qualcomm/qca_7k_common.h b/drivers/net/ethernet/qualcomm/qca_7k_common.h index 928554f11e35..44ed66fdb407 100644 --- a/drivers/net/ethernet/qualcomm/qca_7k_common.h +++ b/drivers/net/ethernet/qualcomm/qca_7k_common.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Atheros Ethernet framing. Every Ethernet frame is surrounded by an atheros @@ -107,9 +94,6 @@ struct qcafrm_handle { /* Offset in buffer (borrowed for length too) */ u16 offset; - - /* Frame length as kept by this module */ - u16 len; }; u16 qcafrm_create_header(u8 *buf, u16 len); @@ -128,17 +112,6 @@ static inline void qcafrm_fsm_init_uart(struct qcafrm_handle *handle) handle->state = handle->init; } -/* Gather received bytes and try to extract a full Ethernet frame - * by following a simple state machine. - * - * Return: QCAFRM_GATHER No Ethernet frame fully received yet. - * QCAFRM_NOHEAD Header expected but not found. - * QCAFRM_INVLEN QCA7K frame length is invalid - * QCAFRM_NOTAIL Footer expected but not found. - * > 0 Number of byte in the fully received - * Ethernet frame - */ - s32 qcafrm_fsm_decode(struct qcafrm_handle *handle, u8 *buf, u16 buf_len, u8 recv_byte); #endif /* _QCA_FRAMING_H */ diff --git a/drivers/net/ethernet/qualcomm/qca_debug.c b/drivers/net/ethernet/qualcomm/qca_debug.c index 1822f2ad8f0d..ff3b89e9028e 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.c +++ b/drivers/net/ethernet/qualcomm/qca_debug.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains debugging routines for use in the QCA7K driver. @@ -255,7 +242,7 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring, struct qcaspi *qca = netdev_priv(dev); ring->rx_max_pending = QCASPI_RX_MAX_FRAMES; - ring->tx_max_pending = TX_RING_MAX_LEN; + ring->tx_max_pending = QCASPI_TX_RING_MAX_LEN; ring->rx_pending = QCASPI_RX_MAX_FRAMES; ring->tx_pending = qca->txr.count; } @@ -275,8 +262,8 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring, if (qca->spi_thread) kthread_park(qca->spi_thread); - qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN); - qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN); + qca->txr.count = max_t(u32, ring->tx_pending, QCASPI_TX_RING_MIN_LEN); + qca->txr.count = min_t(u16, qca->txr.count, QCASPI_TX_RING_MAX_LEN); if (qca->spi_thread) kthread_unpark(qca->spi_thread); diff --git a/drivers/net/ethernet/qualcomm/qca_debug.h b/drivers/net/ethernet/qualcomm/qca_debug.h index 46a785844421..0d98cef3abc4 100644 --- a/drivers/net/ethernet/qualcomm/qca_debug.h +++ b/drivers/net/ethernet/qualcomm/qca_debug.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This file contains debugging routines for use in the QCA7K driver. diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 5f3c11fb3fa2..5799ecc88a87 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This module implements the Qualcomm Atheros SPI protocol for @@ -359,7 +346,7 @@ qcaspi_receive(struct qcaspi *qca) /* Read the packet size. */ qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available); - netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %08x\n", + netdev_dbg(net_dev, "qcaspi_receive: SPI_REG_RDBUF_BYTE_AVA: Value: %04x\n", available); if (available > QCASPI_HW_BUF_LEN + QCASPI_HW_PKT_LEN) { @@ -476,7 +463,7 @@ qcaspi_flush_tx_ring(struct qcaspi *qca) * has been replaced by netif_tx_lock_bh() and so on. */ netif_tx_lock_bh(qca->net_dev); - for (i = 0; i < TX_RING_MAX_LEN; i++) { + for (i = 0; i < QCASPI_TX_RING_MAX_LEN; i++) { if (qca->txr.skb[i]) { dev_kfree_skb(qca->txr.skb[i]); qca->txr.skb[i] = NULL; @@ -687,7 +674,7 @@ static int qcaspi_netdev_open(struct net_device *dev) { struct qcaspi *qca = netdev_priv(dev); - int ret = 0; + struct task_struct *thread; if (!qca) return -EINVAL; @@ -697,23 +684,18 @@ qcaspi_netdev_open(struct net_device *dev) qca->sync = QCASPI_SYNC_UNKNOWN; qcafrm_fsm_init_spi(&qca->frm_handle); - qca->spi_thread = kthread_run((void *)qcaspi_spi_thread, - qca, "%s", dev->name); + thread = kthread_run((void *)qcaspi_spi_thread, + qca, "%s", dev->name); - if (IS_ERR(qca->spi_thread)) { + if (IS_ERR(thread)) { netdev_err(dev, "%s: unable to start kernel thread.\n", QCASPI_DRV_NAME); - return PTR_ERR(qca->spi_thread); + return PTR_ERR(thread); } - ret = request_irq(qca->spi_dev->irq, qcaspi_intr_handler, 0, - dev->name, qca); - if (ret) { - netdev_err(dev, "%s: unable to get IRQ %d (irqval=%d).\n", - QCASPI_DRV_NAME, qca->spi_dev->irq, ret); - kthread_stop(qca->spi_thread); - return ret; - } + qca->spi_thread = thread; + + enable_irq(qca->spi_dev->irq); /* SPI thread takes care of TX queue */ @@ -728,10 +710,12 @@ qcaspi_netdev_close(struct net_device *dev) netif_stop_queue(dev); qcaspi_write_register(qca, SPI_REG_INTR_ENABLE, 0, wr_verify); - free_irq(qca->spi_dev->irq, qca); + disable_irq(qca->spi_dev->irq); - kthread_stop(qca->spi_thread); - qca->spi_thread = NULL; + if (qca->spi_thread) { + kthread_stop(qca->spi_thread); + qca->spi_thread = NULL; + } qcaspi_flush_tx_ring(qca); return 0; @@ -831,8 +815,8 @@ qcaspi_netdev_init(struct net_device *dev) qca->clkspeed = qcaspi_clkspeed; qca->burst_len = qcaspi_burst_len; qca->spi_thread = NULL; - qca->buffer_size = (dev->mtu + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + - QCAFRM_FOOTER_LEN + 4) * 4; + qca->buffer_size = (QCAFRM_MAX_MTU + VLAN_ETH_HLEN + QCAFRM_HEADER_LEN + + QCAFRM_FOOTER_LEN + QCASPI_HW_PKT_LEN) * QCASPI_RX_MAX_FRAMES; memset(&qca->stats, 0, sizeof(struct qcaspi_stats)); @@ -881,6 +865,8 @@ qcaspi_netdev_setup(struct net_device *dev) qcaspi_set_ethtool_ops(dev); dev->watchdog_timeo = QCASPI_TX_TIMEOUT; dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->needed_tailroom = ALIGN(QCAFRM_FOOTER_LEN + QCAFRM_MIN_LEN, 4); + dev->needed_headroom = ALIGN(QCAFRM_HEADER_LEN, 4); dev->tx_queue_len = 100; /* MTU range: 46 - 1500 */ @@ -891,7 +877,7 @@ qcaspi_netdev_setup(struct net_device *dev) memset(qca, 0, sizeof(struct qcaspi)); memset(&qca->txr, 0, sizeof(qca->txr)); - qca->txr.count = TX_RING_MAX_LEN; + qca->txr.count = QCASPI_TX_RING_MAX_LEN; } static const struct of_device_id qca_spi_of_match[] = { @@ -984,6 +970,15 @@ qca_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, qcaspi_devs); + ret = devm_request_irq(&spi->dev, spi->irq, qcaspi_intr_handler, + IRQF_NO_AUTOEN, qca->net_dev->name, qca); + if (ret) { + dev_err(&spi->dev, "Unable to get IRQ %d (irqval=%d).\n", + spi->irq, ret); + free_netdev(qcaspi_devs); + return ret; + } + ret = of_get_ethdev_address(spi->dev.of_node, qca->net_dev); if (ret) { eth_hw_addr_random(qca->net_dev); @@ -998,8 +993,8 @@ qca_spi_probe(struct spi_device *spi) qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE) { - dev_err(&spi->dev, "Invalid signature (0x%04X)\n", - signature); + dev_err(&spi->dev, "Invalid signature (expected 0x%04x, read 0x%04x)\n", + QCASPI_GOOD_SIGNATURE, signature); free_netdev(qcaspi_devs); return -EFAULT; } @@ -1048,6 +1043,6 @@ module_spi_driver(qca_spi_driver); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 SPI Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(QCASPI_DRV_VERSION); diff --git a/drivers/net/ethernet/qualcomm/qca_spi.h b/drivers/net/ethernet/qualcomm/qca_spi.h index 3067356106f0..d59cb2352cee 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.h +++ b/drivers/net/ethernet/qualcomm/qca_spi.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2014, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* Qualcomm Atheros SPI register definition. @@ -39,8 +26,9 @@ #define QCASPI_GOOD_SIGNATURE 0xAA55 -#define TX_RING_MAX_LEN 10 -#define TX_RING_MIN_LEN 2 +#define QCASPI_TX_RING_MAX_LEN 10 +#define QCASPI_TX_RING_MIN_LEN 2 +#define QCASPI_RX_MAX_FRAMES 4 /* sync related constants */ #define QCASPI_SYNC_UNKNOWN 0 @@ -54,7 +42,7 @@ #define QCASPI_EVENT_CPUON 1 struct tx_ring { - struct sk_buff *skb[TX_RING_MAX_LEN]; + struct sk_buff *skb[QCASPI_TX_RING_MAX_LEN]; u16 head; u16 tail; u16 size; diff --git a/drivers/net/ethernet/qualcomm/qca_uart.c b/drivers/net/ethernet/qualcomm/qca_uart.c index 223321897b96..321fd8d00730 100644 --- a/drivers/net/ethernet/qualcomm/qca_uart.c +++ b/drivers/net/ethernet/qualcomm/qca_uart.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* * Copyright (c) 2011, 2012, Qualcomm Atheros Communications Inc. * Copyright (c) 2017, I2SE GmbH - * - * Permission to use, copy, modify, and/or distribute this software - * for any purpose with or without fee is hereby granted, provided - * that the above copyright notice and this permission notice appear - * in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* This module implements the Qualcomm Atheros UART protocol for @@ -410,6 +397,6 @@ module_serdev_device_driver(qca_uart_driver); MODULE_DESCRIPTION("Qualcomm Atheros QCA7000 UART Driver"); MODULE_AUTHOR("Qualcomm Atheros Communications"); -MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_AUTHOR("Stefan Wahren <wahrenst@gmx.net>"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(QCAUART_DRV_VERSION); diff --git a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c index 5b69b9268c75..f3bea196a8f9 100644 --- a/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +++ b/drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c @@ -520,4 +520,5 @@ static void __exit rmnet_exit(void) module_init(rmnet_init) module_exit(rmnet_exit) MODULE_ALIAS_RTNL_LINK("rmnet"); +MODULE_DESCRIPTION("Qualcomm RmNet MAP driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index dd73df6b17b0..3d30d4499791 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -1974,7 +1974,7 @@ static int rtl_set_coalesce(struct net_device *dev, return 0; } -static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) +static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); @@ -1984,7 +1984,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) return phy_ethtool_get_eee(tp->phydev, data); } -static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) +static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); int ret; diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c index 8ba017ec9849..d93b628b7046 100644 --- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c +++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_ethtool.c @@ -133,7 +133,7 @@ static const struct sxgbe_stats sxgbe_gstrings_stats[] = { #define SXGBE_STATS_LEN ARRAY_SIZE(sxgbe_gstrings_stats) static int sxgbe_get_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct sxgbe_priv_data *priv = netdev_priv(dev); @@ -148,7 +148,7 @@ static int sxgbe_get_eee(struct net_device *dev, } static int sxgbe_set_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct sxgbe_priv_data *priv = netdev_priv(dev); diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 758347616535..78ff3af7911a 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -98,6 +98,7 @@ static int watchdog = 1000; module_param(watchdog, int, 0400); MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); +MODULE_DESCRIPTION("SMC 91C9x/91C1xxx Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:smc91x"); diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 31cb7d0166f0..74f1ccc96459 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -56,6 +56,7 @@ #define SMSC_MDIONAME "smsc911x-mdio" #define SMSC_DRV_VERSION "2008-10-21" +MODULE_DESCRIPTION("SMSC LAN911x/LAN921x Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(SMSC_DRV_VERSION); MODULE_ALIAS("platform:smsc911x"); diff --git a/drivers/net/ethernet/smsc/smsc9420.c b/drivers/net/ethernet/smsc/smsc9420.c index e1c4a11c1f18..15cb96c2506d 100644 --- a/drivers/net/ethernet/smsc/smsc9420.c +++ b/drivers/net/ethernet/smsc/smsc9420.c @@ -26,6 +26,7 @@ #define DRV_DESCRIPTION "SMSC LAN9420 driver" #define DRV_VERSION "1.01" +MODULE_DESCRIPTION("SMSC LAN9420 Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 85dcda51df05..4ec61f1ee71a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -165,9 +165,9 @@ config DWMAC_STARFIVE help Support for ethernet controllers on StarFive RISC-V SoCs - This selects the StarFive platform specific glue layer support for - the stmmac device driver. This driver is used for StarFive JH7110 - ethernet controller. + This selects the StarFive platform specific glue layer support + for the stmmac device driver. This driver is used for the + StarFive JH7100 and JH7110 ethernet controllers. config DWMAC_STI tristate "STi GMAC support" diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 721c1f8e892f..70bef7811c91 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -202,6 +202,8 @@ struct stmmac_extra_stats { unsigned long mtl_est_hlbf; unsigned long mtl_est_btre; unsigned long mtl_est_btrlm; + unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES]; + unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES]; /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index ba2ce776bd4d..68f85e4605cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -585,4 +585,5 @@ static struct platform_driver socfpga_dwmac_driver = { }; module_platform_driver(socfpga_dwmac_driver); +MODULE_DESCRIPTION("Altera SOC DWMAC Specific Glue layer"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 5d630affb4d1..4e1076faee0c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -15,13 +15,20 @@ #include "stmmac_platform.h" -#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 -#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 -#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U +#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 +#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 +#define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U + +#define JH7100_SYSMAIN_REGISTER49_DLYCHAIN 0xc8 + +struct starfive_dwmac_data { + unsigned int gtxclk_dlychain; +}; struct starfive_dwmac { struct device *dev; struct clk *clk_tx; + const struct starfive_dwmac_data *data; }; static void starfive_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode) @@ -67,6 +74,8 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: mode = STARFIVE_DWMAC_PHY_INFT_RGMII; break; @@ -89,6 +98,14 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) if (err) return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); + if (dwmac->data) { + err = regmap_write(regmap, JH7100_SYSMAIN_REGISTER49_DLYCHAIN, + dwmac->data->gtxclk_dlychain); + if (err) + return dev_err_probe(dwmac->dev, err, + "error selecting gtxclk delay chain\n"); + } + return 0; } @@ -114,6 +131,8 @@ static int starfive_dwmac_probe(struct platform_device *pdev) if (!dwmac) return -ENOMEM; + dwmac->data = device_get_match_data(&pdev->dev); + dwmac->clk_tx = devm_clk_get_enabled(&pdev->dev, "tx"); if (IS_ERR(dwmac->clk_tx)) return dev_err_probe(&pdev->dev, PTR_ERR(dwmac->clk_tx), @@ -144,8 +163,13 @@ static int starfive_dwmac_probe(struct platform_device *pdev) return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } +static const struct starfive_dwmac_data jh7100_data = { + .gtxclk_dlychain = 4, +}; + static const struct of_device_id starfive_dwmac_match[] = { - { .compatible = "starfive,jh7110-dwmac" }, + { .compatible = "starfive,jh7100-dwmac", .data = &jh7100_data }, + { .compatible = "starfive,jh7110-dwmac" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, starfive_dwmac_match); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c index 4da6ccc17c20..c9693f77e1f6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c @@ -81,6 +81,7 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, u32 status, value, feqn, hbfq, hbfs, btrl, btrl_max; void __iomem *est_addr = priv->estaddr; u32 txqcnt_mask = BIT(txqcnt) - 1; + int i; status = readl(est_addr + EST_STATUS); @@ -125,6 +126,11 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, x->mtl_est_hlbf++; + for (i = 0; i < txqcnt; i++) { + if (feqn & BIT(i)) + x->mtl_est_txq_hlbf[i]++; + } + /* Clear Interrupt */ writel(feqn, est_addr + EST_FRM_SZ_ERR); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 42d27b97dd1d..bbecb3b89535 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -852,7 +852,7 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } static int stmmac_ethtool_op_get_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); @@ -868,7 +868,7 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, } static int stmmac_ethtool_op_set_eee(struct net_device *dev, - struct ethtool_eee *edata) + struct ethtool_keee *edata) { struct stmmac_priv *priv = netdev_priv(dev); int ret; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 25519952f754..04d817dc5899 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2507,6 +2507,13 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) if (!xsk_tx_peek_desc(pool, &xdp_desc)) break; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdp_desc.len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + continue; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) @@ -4501,6 +4508,13 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return stmmac_tso_xmit(skb, dev); } + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + skb->len > priv->plat->est->max_sdu[queue]){ + priv->xstats.max_sdu_txq_drop[queue]++; + goto max_sdu_err; + } + if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) { if (!netif_tx_queue_stopped(netdev_get_tx_queue(dev, queue))) { netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, @@ -4718,6 +4732,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_map_err: netdev_err(priv->dev, "Tx DMA map failed\n"); +max_sdu_err: dev_kfree_skb(skb); priv->xstats.tx_dropped++; return NETDEV_TX_OK; @@ -4874,6 +4889,13 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, if (stmmac_tx_avail(priv, queue) < STMMAC_TX_THRESH(priv)) return STMMAC_XDP_CONSUMED; + if (priv->plat->est && priv->plat->est->enable && + priv->plat->est->max_sdu[queue] && + xdpf->len > priv->plat->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + return STMMAC_XDP_CONSUMED; + } + if (likely(priv->extend_desc)) tx_desc = (struct dma_desc *)(tx_q->dma_etx + entry); else if (tx_q->tbs & STMMAC_TBS_AVAIL) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 26fa33e5ec34..cce00719937d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -915,8 +915,30 @@ struct timespec64 stmmac_calc_tas_basetime(ktime_t old_base_time, return time; } -static int tc_setup_taprio(struct stmmac_priv *priv, - struct tc_taprio_qopt_offload *qopt) +static void tc_taprio_map_maxsdu_txq(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct plat_stmmacenet_data *plat = priv->plat; + u32 num_tc = qopt->mqprio.qopt.num_tc; + u32 offset, count, i, j; + + /* QueueMaxSDU received from the driver corresponds to the Linux traffic + * class. Map queueMaxSDU per Linux traffic class to DWMAC Tx queues. + */ + for (i = 0; i < num_tc; i++) { + if (!qopt->max_sdu[i]) + continue; + + offset = qopt->mqprio.qopt.offset[i]; + count = qopt->mqprio.qopt.count[i]; + + for (j = offset; j < offset + count; j++) + plat->est->max_sdu[j] = qopt->max_sdu[i] + ETH_HLEN - ETH_TLEN; + } +} + +static int tc_taprio_configure(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) { u32 size, wid = priv->dma_cap.estwid, dep = priv->dma_cap.estdep; struct plat_stmmacenet_data *plat = priv->plat; @@ -968,8 +990,6 @@ static int tc_setup_taprio(struct stmmac_priv *priv, if (qopt->cmd == TAPRIO_CMD_DESTROY) goto disable; - else if (qopt->cmd != TAPRIO_CMD_REPLACE) - return -EOPNOTSUPP; if (qopt->num_entries >= dep) return -EINVAL; @@ -1045,6 +1065,8 @@ static int tc_setup_taprio(struct stmmac_priv *priv, priv->plat->est->ter = qopt->cycle_time_extension; + tc_taprio_map_maxsdu_txq(priv, qopt); + if (fpe && !priv->dma_cap.fpesel) { mutex_unlock(&priv->plat->est->lock); return -EOPNOTSUPP; @@ -1078,6 +1100,11 @@ disable: priv->plat->est->enable = false; stmmac_est_configure(priv, priv, priv->plat->est, priv->plat->clk_ptp_rate); + /* Reset taprio status */ + for (i = 0; i < priv->plat->tx_queues_to_use; i++) { + priv->xstats.max_sdu_txq_drop[i] = 0; + priv->xstats.mtl_est_txq_hlbf[i] = 0; + } mutex_unlock(&priv->plat->est->lock); } @@ -1095,6 +1122,57 @@ disable: return ret; } +static void tc_taprio_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + u64 window_drops = 0; + int i = 0; + + for (i = 0; i < priv->plat->tx_queues_to_use; i++) + window_drops += priv->xstats.max_sdu_txq_drop[i] + + priv->xstats.mtl_est_txq_hlbf[i]; + qopt->stats.window_drops = window_drops; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + qopt->stats.tx_overruns = 0; +} + +static void tc_taprio_queue_stats(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + struct tc_taprio_qopt_queue_stats *q_stats = &qopt->queue_stats; + int queue = qopt->queue_stats.queue; + + q_stats->stats.window_drops = priv->xstats.max_sdu_txq_drop[queue] + + priv->xstats.mtl_est_txq_hlbf[queue]; + + /* Transmission overrun doesn't happen for stmmac, hence always 0 */ + q_stats->stats.tx_overruns = 0; +} + +static int tc_setup_taprio(struct stmmac_priv *priv, + struct tc_taprio_qopt_offload *qopt) +{ + int err = 0; + + switch (qopt->cmd) { + case TAPRIO_CMD_REPLACE: + case TAPRIO_CMD_DESTROY: + err = tc_taprio_configure(priv, qopt); + break; + case TAPRIO_CMD_STATS: + tc_taprio_stats(priv, qopt); + break; + case TAPRIO_CMD_QUEUE_STATS: + tc_taprio_queue_stats(priv, qopt); + break; + default: + err = -EOPNOTSUPP; + } + + return err; +} + static int tc_setup_etf(struct stmmac_priv *priv, struct tc_etf_qopt_offload *qopt) { @@ -1126,6 +1204,7 @@ static int tc_query_caps(struct stmmac_priv *priv, return -EOPNOTSUPP; caps->gate_mask_per_txq = true; + caps->supports_queue_max_sdu = true; return 0; } diff --git a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c index 35fceba01ea4..d6ce2c9f0a8d 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-ethtool.c +++ b/drivers/net/ethernet/ti/am65-cpsw-ethtool.c @@ -514,14 +514,14 @@ am65_cpsw_set_link_ksettings(struct net_device *ndev, return phylink_ethtool_ksettings_set(salve->phylink, ecmd); } -static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int am65_cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); return phylink_ethtool_get_eee(salve->phylink, edata); } -static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int am65_cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct am65_cpsw_slave_data *salve = am65_ndev_to_slave(ndev); diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c index 26dc906eae90..57fe936bb177 100644 --- a/drivers/net/ethernet/ti/cpsw-common.c +++ b/drivers/net/ethernet/ti/cpsw-common.c @@ -90,4 +90,5 @@ int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr) } EXPORT_SYMBOL_GPL(ti_cm_get_macid); +MODULE_DESCRIPTION("TI CPSW Switch common module"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/ti/cpsw_ethtool.c b/drivers/net/ethernet/ti/cpsw_ethtool.c index a557a477d039..f7b283353ba2 100644 --- a/drivers/net/ethernet/ti/cpsw_ethtool.c +++ b/drivers/net/ethernet/ti/cpsw_ethtool.c @@ -422,7 +422,7 @@ int cpsw_set_link_ksettings(struct net_device *ndev, return phy_ethtool_ksettings_set(cpsw->slaves[slave_no].phy, ecmd); } -int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; @@ -434,7 +434,7 @@ int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata) return -EOPNOTSUPP; } -int cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +int cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_common *cpsw = priv->cpsw; diff --git a/drivers/net/ethernet/ti/cpsw_priv.h b/drivers/net/ethernet/ti/cpsw_priv.h index 0e27c433098d..7efa72502c86 100644 --- a/drivers/net/ethernet/ti/cpsw_priv.h +++ b/drivers/net/ethernet/ti/cpsw_priv.h @@ -496,8 +496,8 @@ int cpsw_get_link_ksettings(struct net_device *ndev, struct ethtool_link_ksettings *ecmd); int cpsw_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *ecmd); -int cpsw_get_eee(struct net_device *ndev, struct ethtool_eee *edata); -int cpsw_set_eee(struct net_device *ndev, struct ethtool_eee *edata); +int cpsw_get_eee(struct net_device *ndev, struct ethtool_keee *edata); +int cpsw_set_eee(struct net_device *ndev, struct ethtool_keee *edata); int cpsw_nway_reset(struct net_device *ndev); void cpsw_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *ering, diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c index a27ec1dcc8d5..9a7dd7efcf69 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c @@ -45,7 +45,7 @@ static int emac_set_link_ksettings(struct net_device *ndev, return phy_ethtool_set_link_ksettings(ndev, ecmd); } -static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int emac_get_eee(struct net_device *ndev, struct ethtool_keee *edata) { if (!ndev->phydev) return -EOPNOTSUPP; @@ -53,7 +53,7 @@ static int emac_get_eee(struct net_device *ndev, struct ethtool_eee *edata) return phy_ethtool_get_eee(ndev->phydev, edata); } -static int emac_set_eee(struct net_device *ndev, struct ethtool_eee *edata) +static int emac_set_eee(struct net_device *ndev, struct ethtool_keee *edata) { if (!ndev->phydev) return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/wangxun/libwx/wx_hw.c b/drivers/net/ethernet/wangxun/libwx/wx_hw.c index 1db754615cca..945c13d1a982 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_hw.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_hw.c @@ -1958,8 +1958,6 @@ int wx_sw_init(struct wx *wx) return -ENOMEM; } - wx->msix_in_use = false; - return 0; } EXPORT_SYMBOL(wx_sw_init); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index 8706223a6e5a..7cf02ab6de68 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1614,14 +1614,12 @@ static int wx_acquire_msix_vectors(struct wx *wx) /* One for non-queue interrupts */ nvecs += 1; - if (!wx->msix_in_use) { - wx->msix_entry = kcalloc(1, sizeof(struct msix_entry), - GFP_KERNEL); - if (!wx->msix_entry) { - kfree(wx->msix_q_entries); - wx->msix_q_entries = NULL; - return -ENOMEM; - } + wx->msix_entry = kcalloc(1, sizeof(struct msix_entry), + GFP_KERNEL); + if (!wx->msix_entry) { + kfree(wx->msix_q_entries); + wx->msix_q_entries = NULL; + return -ENOMEM; } nvecs = pci_alloc_irq_vectors_affinity(wx->pdev, nvecs, @@ -1931,10 +1929,8 @@ void wx_reset_interrupt_capability(struct wx *wx) if (pdev->msix_enabled) { kfree(wx->msix_q_entries); wx->msix_q_entries = NULL; - if (!wx->msix_in_use) { - kfree(wx->msix_entry); - wx->msix_entry = NULL; - } + kfree(wx->msix_entry); + wx->msix_entry = NULL; } pci_free_irq_vectors(wx->pdev); } diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index b4dc4f341117..1fdeb464d5f4 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -1047,7 +1047,6 @@ struct wx { unsigned int queues_per_pool; struct msix_entry *msix_q_entries; struct msix_entry *msix_entry; - bool msix_in_use; struct wx_ring_feature ring_feature[RING_F_ARRAY_SIZE]; /* misc interrupt status block */ diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile index 7507f762edfe..42718875277c 100644 --- a/drivers/net/ethernet/wangxun/txgbe/Makefile +++ b/drivers/net/ethernet/wangxun/txgbe/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o txgbe-objs := txgbe_main.o \ txgbe_hw.o \ txgbe_phy.o \ + txgbe_irq.o \ txgbe_ethtool.o diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c new file mode 100644 index 000000000000..b3e3605d1edb --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ + +#include <linux/irqdomain.h> +#include <linux/pci.h> + +#include "../libwx/wx_type.h" +#include "../libwx/wx_lib.h" +#include "../libwx/wx_hw.h" +#include "txgbe_type.h" +#include "txgbe_phy.h" +#include "txgbe_irq.h" + +/** + * txgbe_irq_enable - Enable default interrupt generation settings + * @wx: pointer to private structure + * @queues: enable irqs for queues + **/ +void txgbe_irq_enable(struct wx *wx, bool queues) +{ + wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); + + /* unmask interrupt */ + wx_intr_enable(wx, TXGBE_INTR_MISC); + if (queues) + wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); +} + +/** + * txgbe_intr - msi/legacy mode Interrupt Handler + * @irq: interrupt number + * @data: pointer to a network interface device structure + **/ +static irqreturn_t txgbe_intr(int __always_unused irq, void *data) +{ + struct wx_q_vector *q_vector; + struct wx *wx = data; + struct pci_dev *pdev; + u32 eicr; + + q_vector = wx->q_vector[0]; + pdev = wx->pdev; + + eicr = wx_misc_isb(wx, WX_ISB_VEC0); + if (!eicr) { + /* shared interrupt alert! + * the interrupt that we masked before the ICR read. + */ + if (netif_running(wx->netdev)) + txgbe_irq_enable(wx, true); + return IRQ_NONE; /* Not our interrupt */ + } + wx->isb_mem[WX_ISB_VEC0] = 0; + if (!(pdev->msi_enabled)) + wr32(wx, WX_PX_INTA, 1); + + wx->isb_mem[WX_ISB_MISC] = 0; + /* would disable interrupts here but it is auto disabled */ + napi_schedule_irqoff(&q_vector->napi); + + /* re-enable link(maybe) and non-queue interrupts, no flush. + * txgbe_poll will re-enable the queue interrupts + */ + if (netif_running(wx->netdev)) + txgbe_irq_enable(wx, false); + + return IRQ_HANDLED; +} + +/** + * txgbe_request_msix_irqs - Initialize MSI-X interrupts + * @wx: board private structure + * + * Allocate MSI-X vectors and request interrupts from the kernel. + **/ +static int txgbe_request_msix_irqs(struct wx *wx) +{ + struct net_device *netdev = wx->netdev; + int vector, err; + + for (vector = 0; vector < wx->num_q_vectors; vector++) { + struct wx_q_vector *q_vector = wx->q_vector[vector]; + struct msix_entry *entry = &wx->msix_q_entries[vector]; + + if (q_vector->tx.ring && q_vector->rx.ring) + snprintf(q_vector->name, sizeof(q_vector->name) - 1, + "%s-TxRx-%d", netdev->name, entry->entry); + else + /* skip this unused q_vector */ + continue; + + err = request_irq(entry->vector, wx_msix_clean_rings, 0, + q_vector->name, q_vector); + if (err) { + wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", + q_vector->name, err); + goto free_queue_irqs; + } + } + + return 0; + +free_queue_irqs: + while (vector) { + vector--; + free_irq(wx->msix_q_entries[vector].vector, + wx->q_vector[vector]); + } + wx_reset_interrupt_capability(wx); + return err; +} + +/** + * txgbe_request_irq - initialize interrupts + * @wx: board private structure + * + * Attempt to configure interrupts using the best available + * capabilities of the hardware and kernel. + **/ +int txgbe_request_irq(struct wx *wx) +{ + struct net_device *netdev = wx->netdev; + struct pci_dev *pdev = wx->pdev; + int err; + + if (pdev->msix_enabled) + err = txgbe_request_msix_irqs(wx); + else if (pdev->msi_enabled) + err = request_irq(wx->pdev->irq, &txgbe_intr, 0, + netdev->name, wx); + else + err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, + netdev->name, wx); + + if (err) + wx_err(wx, "request_irq failed, Error %d\n", err); + + return err; +} + +static int txgbe_request_gpio_irq(struct txgbe *txgbe) +{ + txgbe->gpio_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); + return request_threaded_irq(txgbe->gpio_irq, NULL, + txgbe_gpio_irq_handler, + IRQF_ONESHOT, "txgbe-gpio-irq", txgbe); +} + +static int txgbe_request_link_irq(struct txgbe *txgbe) +{ + txgbe->link_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); + return request_threaded_irq(txgbe->link_irq, NULL, + txgbe_link_irq_handler, + IRQF_ONESHOT, "txgbe-link-irq", txgbe); +} + +static const struct irq_chip txgbe_irq_chip = { + .name = "txgbe-misc-irq", +}; + +static int txgbe_misc_irq_domain_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hwirq) +{ + struct txgbe *txgbe = d->host_data; + + irq_set_chip_data(irq, txgbe); + irq_set_chip(irq, &txgbe->misc.chip); + irq_set_nested_thread(irq, true); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops txgbe_misc_irq_domain_ops = { + .map = txgbe_misc_irq_domain_map, +}; + +static irqreturn_t txgbe_misc_irq_handle(int irq, void *data) +{ + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; + unsigned int nhandled = 0; + unsigned int sub_irq; + u32 eicr; + + eicr = wx_misc_isb(wx, WX_ISB_MISC); + if (eicr & TXGBE_PX_MISC_GPIO) { + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_GPIO); + handle_nested_irq(sub_irq); + nhandled++; + } + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | + TXGBE_PX_MISC_ETH_AN)) { + sub_irq = irq_find_mapping(txgbe->misc.domain, TXGBE_IRQ_LINK); + handle_nested_irq(sub_irq); + nhandled++; + } + + wx_intr_enable(wx, TXGBE_INTR_MISC); + return (nhandled > 0 ? IRQ_HANDLED : IRQ_NONE); +} + +static void txgbe_del_irq_domain(struct txgbe *txgbe) +{ + int hwirq, virq; + + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) { + virq = irq_find_mapping(txgbe->misc.domain, hwirq); + irq_dispose_mapping(virq); + } + + irq_domain_remove(txgbe->misc.domain); +} + +void txgbe_free_misc_irq(struct txgbe *txgbe) +{ + free_irq(txgbe->gpio_irq, txgbe); + free_irq(txgbe->link_irq, txgbe); + free_irq(txgbe->misc.irq, txgbe); + txgbe_del_irq_domain(txgbe); +} + +int txgbe_setup_misc_irq(struct txgbe *txgbe) +{ + struct wx *wx = txgbe->wx; + int hwirq, err; + + txgbe->misc.nirqs = 2; + txgbe->misc.domain = irq_domain_add_simple(NULL, txgbe->misc.nirqs, 0, + &txgbe_misc_irq_domain_ops, txgbe); + if (!txgbe->misc.domain) + return -ENOMEM; + + for (hwirq = 0; hwirq < txgbe->misc.nirqs; hwirq++) + irq_create_mapping(txgbe->misc.domain, hwirq); + + txgbe->misc.chip = txgbe_irq_chip; + if (wx->pdev->msix_enabled) + txgbe->misc.irq = wx->msix_entry->vector; + else + txgbe->misc.irq = wx->pdev->irq; + + err = request_threaded_irq(txgbe->misc.irq, NULL, + txgbe_misc_irq_handle, + IRQF_ONESHOT, + wx->netdev->name, txgbe); + if (err) + goto del_misc_irq; + + err = txgbe_request_gpio_irq(txgbe); + if (err) + goto free_msic_irq; + + err = txgbe_request_link_irq(txgbe); + if (err) + goto free_gpio_irq; + + return 0; + +free_gpio_irq: + free_irq(txgbe->gpio_irq, txgbe); +free_msic_irq: + free_irq(txgbe->misc.irq, txgbe); +del_misc_irq: + txgbe_del_irq_domain(txgbe); + + return err; +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h new file mode 100644 index 000000000000..b77945e7a0f2 --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2024 Beijing WangXun Technology Co., Ltd. */ + +void txgbe_irq_enable(struct wx *wx, bool queues); +int txgbe_request_irq(struct wx *wx); +void txgbe_free_misc_irq(struct txgbe *txgbe); +int txgbe_setup_misc_irq(struct txgbe *txgbe); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 3b151c410a5c..e67a21294158 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -17,6 +17,7 @@ #include "txgbe_type.h" #include "txgbe_hw.h" #include "txgbe_phy.h" +#include "txgbe_irq.h" #include "txgbe_ethtool.h" char txgbe_driver_name[] = "txgbe"; @@ -76,133 +77,6 @@ static int txgbe_enumerate_functions(struct wx *wx) return physfns; } -/** - * txgbe_irq_enable - Enable default interrupt generation settings - * @wx: pointer to private structure - * @queues: enable irqs for queues - **/ -static void txgbe_irq_enable(struct wx *wx, bool queues) -{ - wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); - - /* unmask interrupt */ - wx_intr_enable(wx, TXGBE_INTR_MISC); - if (queues) - wx_intr_enable(wx, TXGBE_INTR_QALL(wx)); -} - -/** - * txgbe_intr - msi/legacy mode Interrupt Handler - * @irq: interrupt number - * @data: pointer to a network interface device structure - **/ -static irqreturn_t txgbe_intr(int __always_unused irq, void *data) -{ - struct wx_q_vector *q_vector; - struct wx *wx = data; - struct pci_dev *pdev; - u32 eicr; - - q_vector = wx->q_vector[0]; - pdev = wx->pdev; - - eicr = wx_misc_isb(wx, WX_ISB_VEC0); - if (!eicr) { - /* shared interrupt alert! - * the interrupt that we masked before the ICR read. - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, true); - return IRQ_NONE; /* Not our interrupt */ - } - wx->isb_mem[WX_ISB_VEC0] = 0; - if (!(pdev->msi_enabled)) - wr32(wx, WX_PX_INTA, 1); - - wx->isb_mem[WX_ISB_MISC] = 0; - /* would disable interrupts here but it is auto disabled */ - napi_schedule_irqoff(&q_vector->napi); - - /* re-enable link(maybe) and non-queue interrupts, no flush. - * txgbe_poll will re-enable the queue interrupts - */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, false); - - return IRQ_HANDLED; -} - -/** - * txgbe_request_msix_irqs - Initialize MSI-X interrupts - * @wx: board private structure - * - * Allocate MSI-X vectors and request interrupts from the kernel. - **/ -static int txgbe_request_msix_irqs(struct wx *wx) -{ - struct net_device *netdev = wx->netdev; - int vector, err; - - for (vector = 0; vector < wx->num_q_vectors; vector++) { - struct wx_q_vector *q_vector = wx->q_vector[vector]; - struct msix_entry *entry = &wx->msix_q_entries[vector]; - - if (q_vector->tx.ring && q_vector->rx.ring) - snprintf(q_vector->name, sizeof(q_vector->name) - 1, - "%s-TxRx-%d", netdev->name, entry->entry); - else - /* skip this unused q_vector */ - continue; - - err = request_irq(entry->vector, wx_msix_clean_rings, 0, - q_vector->name, q_vector); - if (err) { - wx_err(wx, "request_irq failed for MSIX interrupt %s Error: %d\n", - q_vector->name, err); - goto free_queue_irqs; - } - } - - return 0; - -free_queue_irqs: - while (vector) { - vector--; - free_irq(wx->msix_q_entries[vector].vector, - wx->q_vector[vector]); - } - wx_reset_interrupt_capability(wx); - return err; -} - -/** - * txgbe_request_irq - initialize interrupts - * @wx: board private structure - * - * Attempt to configure interrupts using the best available - * capabilities of the hardware and kernel. - **/ -static int txgbe_request_irq(struct wx *wx) -{ - struct net_device *netdev = wx->netdev; - struct pci_dev *pdev = wx->pdev; - int err; - - if (pdev->msix_enabled) - err = txgbe_request_msix_irqs(wx); - else if (pdev->msi_enabled) - err = request_irq(wx->pdev->irq, &txgbe_intr, 0, - netdev->name, wx); - else - err = request_irq(wx->pdev->irq, &txgbe_intr, IRQF_SHARED, - netdev->name, wx); - - if (err) - wx_err(wx, "request_irq failed, Error %d\n", err); - - return err; -} - static void txgbe_up_complete(struct wx *wx) { struct net_device *netdev = wx->netdev; @@ -518,6 +392,7 @@ static void txgbe_shutdown(struct pci_dev *pdev) int txgbe_setup_tc(struct net_device *dev, u8 tc) { struct wx *wx = netdev_priv(dev); + struct txgbe *txgbe = wx->priv; /* Hardware has to reinitialize queues and interrupts to * match packet buffer alignment. Unfortunately, the @@ -528,6 +403,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) else txgbe_reset(wx); + txgbe_free_misc_irq(txgbe); wx_clear_interrupt_scheme(wx); if (tc) @@ -536,6 +412,7 @@ int txgbe_setup_tc(struct net_device *dev, u8 tc) netdev_reset_tc(dev); wx_init_interrupt_scheme(wx); + txgbe_setup_misc_irq(txgbe); if (netif_running(dev)) txgbe_open(dev); @@ -751,10 +628,14 @@ static int txgbe_probe(struct pci_dev *pdev, txgbe->wx = wx; wx->priv = txgbe; - err = txgbe_init_phy(txgbe); + err = txgbe_setup_misc_irq(txgbe); if (err) goto err_release_hw; + err = txgbe_init_phy(txgbe); + if (err) + goto err_free_misc_irq; + err = register_netdev(netdev); if (err) goto err_remove_phy; @@ -781,6 +662,8 @@ static int txgbe_probe(struct pci_dev *pdev, err_remove_phy: txgbe_remove_phy(txgbe); +err_free_misc_irq: + txgbe_free_misc_irq(txgbe); err_release_hw: wx_clear_interrupt_scheme(wx); wx_control_hw(wx, false); @@ -813,6 +696,7 @@ static void txgbe_remove(struct pci_dev *pdev) unregister_netdev(netdev); txgbe_remove_phy(txgbe); + txgbe_free_misc_irq(txgbe); pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 1b84d495d14e..bae0a8ee7014 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -292,6 +292,21 @@ static int txgbe_phylink_init(struct txgbe *txgbe) return 0; } +irqreturn_t txgbe_link_irq_handler(int irq, void *data) +{ + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; + u32 status; + bool up; + + status = rd32(wx, TXGBE_CFG_PORT_ST); + up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP); + + phylink_mac_change(wx->phylink, up); + + return IRQ_HANDLED; +} + static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct wx *wx = gpiochip_get_data(chip); @@ -437,7 +452,7 @@ static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type) } static const struct irq_chip txgbe_gpio_irq_chip = { - .name = "txgbe_gpio_irq", + .name = "txgbe-gpio-irq", .irq_ack = txgbe_gpio_irq_ack, .irq_mask = txgbe_gpio_irq_mask, .irq_unmask = txgbe_gpio_irq_unmask, @@ -446,20 +461,14 @@ static const struct irq_chip txgbe_gpio_irq_chip = { GPIOCHIP_IRQ_RESOURCE_HELPERS, }; -static void txgbe_irq_handler(struct irq_desc *desc) +irqreturn_t txgbe_gpio_irq_handler(int irq, void *data) { - struct irq_chip *chip = irq_desc_get_chip(desc); - struct wx *wx = irq_desc_get_handler_data(desc); - struct txgbe *txgbe = wx->priv; + struct txgbe *txgbe = data; + struct wx *wx = txgbe->wx; irq_hw_number_t hwirq; unsigned long gpioirq; struct gpio_chip *gc; unsigned long flags; - u32 eicr; - - eicr = wx_misc_isb(wx, WX_ISB_MISC); - - chained_irq_enter(chip, desc); gpioirq = rd32(wx, WX_GPIO_INTSTATUS); @@ -468,7 +477,7 @@ static void txgbe_irq_handler(struct irq_desc *desc) int gpio = irq_find_mapping(gc->irq.domain, hwirq); u32 irq_type = irq_get_trigger_type(gpio); - generic_handle_domain_irq(gc->irq.domain, hwirq); + handle_nested_irq(gpio); if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { raw_spin_lock_irqsave(&wx->gpio_lock, flags); @@ -477,17 +486,7 @@ static void txgbe_irq_handler(struct irq_desc *desc) } } - chained_irq_exit(chip, desc); - - if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | - TXGBE_PX_MISC_ETH_AN)) { - u32 reg = rd32(wx, TXGBE_CFG_PORT_ST); - - phylink_mac_change(wx->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); - } - - /* unmask interrupt */ - wx_intr_enable(wx, TXGBE_INTR_MISC); + return IRQ_HANDLED; } static int txgbe_gpio_init(struct txgbe *txgbe) @@ -524,19 +523,6 @@ static int txgbe_gpio_init(struct txgbe *txgbe) girq = &gc->irq; gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip); - girq->parent_handler = txgbe_irq_handler; - girq->parent_handler_data = wx; - girq->num_parents = 1; - girq->parents = devm_kcalloc(dev, girq->num_parents, - sizeof(*girq->parents), GFP_KERNEL); - if (!girq->parents) - return -ENOMEM; - - /* now only suuported on MSI-X interrupt */ - if (!wx->msix_entry) - return -EPERM; - - girq->parents[0] = wx->msix_entry->vector; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; @@ -754,8 +740,6 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err_unregister_i2c; } - wx->msix_in_use = true; - return 0; err_unregister_i2c: @@ -788,5 +772,4 @@ void txgbe_remove_phy(struct txgbe *txgbe) phylink_destroy(txgbe->wx->phylink); xpcs_destroy(txgbe->xpcs); software_node_unregister_node_group(txgbe->nodes.group); - txgbe->wx->msix_in_use = false; } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h index 1ab592124986..9855d44076cb 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -4,6 +4,8 @@ #ifndef _TXGBE_PHY_H_ #define _TXGBE_PHY_H_ +irqreturn_t txgbe_gpio_irq_handler(int irq, void *data); +irqreturn_t txgbe_link_irq_handler(int irq, void *data); int txgbe_init_phy(struct txgbe *txgbe); void txgbe_remove_phy(struct txgbe *txgbe); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 270a6fd9ad0b..1b4ff50d5857 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -5,6 +5,7 @@ #define _TXGBE_TYPE_H_ #include <linux/property.h> +#include <linux/irq.h> /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 @@ -169,15 +170,31 @@ struct txgbe_nodes { const struct software_node *group[SWNODE_MAX + 1]; }; +enum txgbe_misc_irqs { + TXGBE_IRQ_GPIO = 0, + TXGBE_IRQ_LINK, + TXGBE_IRQ_MAX +}; + +struct txgbe_irq { + struct irq_chip chip; + struct irq_domain *domain; + int nirqs; + int irq; +}; + struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct txgbe_irq misc; struct dw_xpcs *xpcs; struct platform_device *sfp_dev; struct platform_device *i2c_dev; struct clk_lookup *clock; struct clk *clk; struct gpio_chip *gpio; + unsigned int gpio_irq; + unsigned int link_irq; }; #endif /* _TXGBE_TYPE_H_ */ diff --git a/drivers/net/pcs/pcs-lynx.c b/drivers/net/pcs/pcs-lynx.c index dc3962b2aa6b..853b8c138718 100644 --- a/drivers/net/pcs/pcs-lynx.c +++ b/drivers/net/pcs/pcs-lynx.c @@ -398,4 +398,5 @@ void lynx_pcs_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(lynx_pcs_destroy); +MODULE_DESCRIPTION("NXP Lynx PCS phylink library"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/pcs/pcs-mtk-lynxi.c b/drivers/net/pcs/pcs-mtk-lynxi.c index 8501dd365279..4f63abe638c4 100644 --- a/drivers/net/pcs/pcs-mtk-lynxi.c +++ b/drivers/net/pcs/pcs-mtk-lynxi.c @@ -303,4 +303,5 @@ void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs) } EXPORT_SYMBOL(mtk_pcs_lynxi_destroy); +MODULE_DESCRIPTION("MediaTek SGMII library for LynxI"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c index 31f0beba638a..52a7757ee419 100644 --- a/drivers/net/pcs/pcs-xpcs.c +++ b/drivers/net/pcs/pcs-xpcs.c @@ -1456,4 +1456,5 @@ struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr, } EXPORT_SYMBOL_GPL(xpcs_create_mdiodev); +MODULE_DESCRIPTION("Synopsys DesignWare XPCS library"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 9e2672800f0b..e261e58bf158 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -335,12 +335,7 @@ config NCN26000_PHY Currently supports the NCN26000 10BASE-T1S Industrial PHY with MII interface. -config AT803X_PHY - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs" - depends on REGULATOR - help - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal - QCA8337(Internal qca8k PHY) model +source "drivers/net/phy/qcom/Kconfig" config QSEMI_PHY tristate "Quality Semiconductor PHYs" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 6097afd44392..197acfa0b412 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_ADIN_PHY) += adin.o obj-$(CONFIG_ADIN1100_PHY) += adin1100.o obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ -obj-$(CONFIG_AT803X_PHY) += at803x.o ifdef CONFIG_AX88796B_RUST_PHY obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o else @@ -91,6 +90,7 @@ endif obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp-c45-tja.o obj-$(CONFIG_NXP_CBTX_PHY) += nxp-cbtx.o obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o +obj-y += qcom/ obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_REALTEK_PHY) += realtek.o obj-$(CONFIG_RENESAS_PHY) += uPD60620.o diff --git a/drivers/net/phy/adin1100.c b/drivers/net/phy/adin1100.c index 7619d6185801..85f910e2d4fb 100644 --- a/drivers/net/phy/adin1100.c +++ b/drivers/net/phy/adin1100.c @@ -18,6 +18,12 @@ #define PHY_ID_ADIN1110 0x0283bc91 #define PHY_ID_ADIN2111 0x0283bca1 +#define ADIN_PHY_SUBSYS_IRQ_MASK 0x0021 +#define ADIN_LINK_STAT_CHNG_IRQ_EN BIT(1) + +#define ADIN_PHY_SUBSYS_IRQ_STATUS 0x0011 +#define ADIN_LINK_STAT_CHNG BIT(1) + #define ADIN_FORCED_MODE 0x8000 #define ADIN_FORCED_MODE_EN BIT(0) @@ -136,6 +142,53 @@ static int adin_config_aneg(struct phy_device *phydev) return genphy_c45_config_aneg(phydev); } +static int adin_phy_ack_intr(struct phy_device *phydev) +{ + /* Clear pending interrupts */ + int rc = phy_read_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_STATUS); + + return rc < 0 ? rc : 0; +} + +static int adin_config_intr(struct phy_device *phydev) +{ + u16 irq_mask; + int ret; + + ret = adin_phy_ack_intr(phydev); + if (ret) + return ret; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + irq_mask = ADIN_LINK_STAT_CHNG_IRQ_EN; + else + irq_mask = 0; + + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_MASK, + ADIN_LINK_STAT_CHNG_IRQ_EN, irq_mask); +} + +static irqreturn_t adin_phy_handle_interrupt(struct phy_device *phydev) +{ + int irq_status; + + irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, + ADIN_PHY_SUBSYS_IRQ_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + if (!(irq_status & ADIN_LINK_STAT_CHNG)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} + static int adin_set_powerdown_mode(struct phy_device *phydev, bool en) { int ret; @@ -275,6 +328,8 @@ static struct phy_driver adin_driver[] = { .probe = adin_probe, .config_aneg = adin_config_aneg, .read_status = adin_read_status, + .config_intr = adin_config_intr, + .handle_interrupt = adin_phy_handle_interrupt, .set_loopback = adin_set_loopback, .suspend = adin_suspend, .resume = adin_resume, diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c deleted file mode 100644 index a62442a55774..000000000000 --- a/drivers/net/phy/at803x.c +++ /dev/null @@ -1,2432 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * drivers/net/phy/at803x.c - * - * Driver for Qualcomm Atheros AR803x PHY - * - * Author: Matus Ujhelyi <ujhelyi.m@gmail.com> - */ - -#include <linux/phy.h> -#include <linux/module.h> -#include <linux/string.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/ethtool_netlink.h> -#include <linux/bitfield.h> -#include <linux/regulator/of_regulator.h> -#include <linux/regulator/driver.h> -#include <linux/regulator/consumer.h> -#include <linux/of.h> -#include <linux/phylink.h> -#include <linux/sfp.h> -#include <dt-bindings/net/qca-ar803x.h> - -#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 -#define AT803X_SFC_ASSERT_CRS BIT(11) -#define AT803X_SFC_FORCE_LINK BIT(10) -#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) -#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 -#define AT803X_SFC_MANUAL_MDIX 0x1 -#define AT803X_SFC_MANUAL_MDI 0x0 -#define AT803X_SFC_SQE_TEST BIT(2) -#define AT803X_SFC_POLARITY_REVERSAL BIT(1) -#define AT803X_SFC_DISABLE_JABBER BIT(0) - -#define AT803X_SPECIFIC_STATUS 0x11 -#define AT803X_SS_SPEED_MASK GENMASK(15, 14) -#define AT803X_SS_SPEED_1000 2 -#define AT803X_SS_SPEED_100 1 -#define AT803X_SS_SPEED_10 0 -#define AT803X_SS_DUPLEX BIT(13) -#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) -#define AT803X_SS_MDIX BIT(6) - -#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) -#define QCA808X_SS_SPEED_2500 4 - -#define AT803X_INTR_ENABLE 0x12 -#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) -#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) -#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) -#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) -#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) -#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) -#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) -#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) -#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) -#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) -#define AT803X_INTR_ENABLE_WOL BIT(0) - -#define AT803X_INTR_STATUS 0x13 - -#define AT803X_SMART_SPEED 0x14 -#define AT803X_SMART_SPEED_ENABLE BIT(5) -#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) -#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) -#define AT803X_CDT 0x16 -#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) -#define AT803X_CDT_ENABLE_TEST BIT(0) -#define AT803X_CDT_STATUS 0x1c -#define AT803X_CDT_STATUS_STAT_NORMAL 0 -#define AT803X_CDT_STATUS_STAT_SHORT 1 -#define AT803X_CDT_STATUS_STAT_OPEN 2 -#define AT803X_CDT_STATUS_STAT_FAIL 3 -#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) -#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) -#define AT803X_LED_CONTROL 0x18 - -#define AT803X_PHY_MMD3_WOL_CTRL 0x8012 -#define AT803X_WOL_EN BIT(5) -#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C -#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B -#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A -#define AT803X_REG_CHIP_CONFIG 0x1f -#define AT803X_BT_BX_REG_SEL 0x8000 - -#define AT803X_DEBUG_ADDR 0x1D -#define AT803X_DEBUG_DATA 0x1E - -#define AT803X_MODE_CFG_MASK 0x0F -#define AT803X_MODE_CFG_BASET_RGMII 0x00 -#define AT803X_MODE_CFG_BASET_SGMII 0x01 -#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 -#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 -#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 -#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 -#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 -#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 -#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B -#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E -#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F - -#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ -#define AT803X_PSSR_MR_AN_COMPLETE 0x0200 - -#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 -#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) -#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) -#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) - -#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 -#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) - -#define AT803X_DEBUG_REG_HIB_CTRL 0x0b -#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) -#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) -#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) - -#define AT803X_DEBUG_REG_3C 0x3C - -#define AT803X_DEBUG_REG_GREEN 0x3D -#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) - -#define AT803X_DEBUG_REG_1F 0x1F -#define AT803X_DEBUG_PLL_ON BIT(2) -#define AT803X_DEBUG_RGMII_1V8 BIT(3) - -#define MDIO_AZ_DEBUG 0x800D - -/* AT803x supports either the XTAL input pad, an internal PLL or the - * DSP as clock reference for the clock output pad. The XTAL reference - * is only used for 25 MHz output, all other frequencies need the PLL. - * The DSP as a clock reference is used in synchronous ethernet - * applications. - * - * By default the PLL is only enabled if there is a link. Otherwise - * the PHY will go into low power state and disabled the PLL. You can - * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always - * enabled. - */ -#define AT803X_MMD7_CLK25M 0x8016 -#define AT803X_CLK_OUT_MASK GENMASK(4, 2) -#define AT803X_CLK_OUT_25MHZ_XTAL 0 -#define AT803X_CLK_OUT_25MHZ_DSP 1 -#define AT803X_CLK_OUT_50MHZ_PLL 2 -#define AT803X_CLK_OUT_50MHZ_DSP 3 -#define AT803X_CLK_OUT_62_5MHZ_PLL 4 -#define AT803X_CLK_OUT_62_5MHZ_DSP 5 -#define AT803X_CLK_OUT_125MHZ_PLL 6 -#define AT803X_CLK_OUT_125MHZ_DSP 7 - -/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask - * but doesn't support choosing between XTAL/PLL and DSP. - */ -#define AT8035_CLK_OUT_MASK GENMASK(4, 3) - -#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) -#define AT803X_CLK_OUT_STRENGTH_FULL 0 -#define AT803X_CLK_OUT_STRENGTH_HALF 1 -#define AT803X_CLK_OUT_STRENGTH_QUARTER 2 - -#define AT803X_DEFAULT_DOWNSHIFT 5 -#define AT803X_MIN_DOWNSHIFT 2 -#define AT803X_MAX_DOWNSHIFT 9 - -#define AT803X_MMD3_SMARTEEE_CTL1 0x805b -#define AT803X_MMD3_SMARTEEE_CTL2 0x805c -#define AT803X_MMD3_SMARTEEE_CTL3 0x805d -#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8) - -#define ATH9331_PHY_ID 0x004dd041 -#define ATH8030_PHY_ID 0x004dd076 -#define ATH8031_PHY_ID 0x004dd074 -#define ATH8032_PHY_ID 0x004dd023 -#define ATH8035_PHY_ID 0x004dd072 -#define AT8030_PHY_ID_MASK 0xffffffef - -#define QCA8081_PHY_ID 0x004dd101 - -#define QCA8327_A_PHY_ID 0x004dd033 -#define QCA8327_B_PHY_ID 0x004dd034 -#define QCA8337_PHY_ID 0x004dd036 -#define QCA9561_PHY_ID 0x004dd042 -#define QCA8K_PHY_ID_MASK 0xffffffff - -#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) - -#define AT803X_PAGE_FIBER 0 -#define AT803X_PAGE_COPPER 1 - -/* don't turn off internal PLL */ -#define AT803X_KEEP_PLL_ENABLED BIT(0) -#define AT803X_DISABLE_SMARTEEE BIT(1) - -/* disable hibernation mode */ -#define AT803X_DISABLE_HIBERNATION_MODE BIT(2) - -/* ADC threshold */ -#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 -#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) -#define QCA808X_ADC_THRESHOLD_80MV 0 -#define QCA808X_ADC_THRESHOLD_100MV 0xf0 -#define QCA808X_ADC_THRESHOLD_200MV 0x0f -#define QCA808X_ADC_THRESHOLD_300MV 0xff - -/* CLD control */ -#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 -#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) -#define QCA808X_8023AZ_AFE_EN 0x90 - -/* AZ control */ -#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 -#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 -#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E -#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E -#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 - -#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 -#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 - -#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c -#define QCA808X_TOP_OPTION1_DATA 0x0 - -#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 -#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 -#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 -#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad -#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 -#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 -#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 -#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 -#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 -#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 -#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 -#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 - -/* master/slave seed config */ -#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 -#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) -#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) -#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 - -/* Hibernation yields lower power consumpiton in contrast with normal operation mode. - * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. - */ -#define QCA808X_DBG_AN_TEST 0xb -#define QCA808X_HIBERNATION_EN BIT(15) - -#define QCA808X_CDT_ENABLE_TEST BIT(15) -#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) -#define QCA808X_CDT_STATUS BIT(11) -#define QCA808X_CDT_LENGTH_UNIT BIT(10) - -#define QCA808X_MMD3_CDT_STATUS 0x8064 -#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 -#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 -#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 -#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 -#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) -#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) - -#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) -#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) -#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) -#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) - -#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) -#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) -#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) -#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) -#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) - -#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) -#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) -#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) -#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) - -/* NORMAL are MDI with type set to 0 */ -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI1) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI2) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ - QCA808X_CDT_STATUS_STAT_MDI3) -#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ - QCA808X_CDT_STATUS_STAT_MDI3) - -/* Added for reference of existence but should be handled by wait_for_completion already */ -#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) - -/* QCA808X 1G chip type */ -#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d -#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) - -#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 -#define QCA8081_PHY_FIFO_RSTN BIT(11) - -MODULE_DESCRIPTION("Qualcomm Atheros AR803x and QCA808X PHY driver"); -MODULE_AUTHOR("Matus Ujhelyi"); -MODULE_LICENSE("GPL"); - -enum stat_access_type { - PHY, - MMD -}; - -struct at803x_hw_stat { - const char *string; - u8 reg; - u32 mask; - enum stat_access_type access_type; -}; - -static struct at803x_hw_stat qca83xx_hw_stats[] = { - { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, - { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, - { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, -}; - -struct at803x_ss_mask { - u16 speed_mask; - u8 speed_shift; -}; - -struct at803x_priv { - int flags; - u16 clk_25m_reg; - u16 clk_25m_mask; - u8 smarteee_lpi_tw_1g; - u8 smarteee_lpi_tw_100m; - bool is_fiber; - bool is_1000basex; - struct regulator_dev *vddio_rdev; - struct regulator_dev *vddh_rdev; - u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; -}; - -struct at803x_context { - u16 bmcr; - u16 advertise; - u16 control1000; - u16 int_enable; - u16 smart_speed; - u16 led_control; -}; - -static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_write(phydev, AT803X_DEBUG_DATA, data); -} - -static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) -{ - int ret; - - ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); - if (ret < 0) - return ret; - - return phy_read(phydev, AT803X_DEBUG_DATA); -} - -static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, - u16 clear, u16 set) -{ - u16 val; - int ret; - - ret = at803x_debug_reg_read(phydev, reg); - if (ret < 0) - return ret; - - val = ret & 0xffff; - val &= ~clear; - val |= set; - - return phy_write(phydev, AT803X_DEBUG_DATA, val); -} - -static int at803x_write_page(struct phy_device *phydev, int page) -{ - int mask; - int set; - - if (page == AT803X_PAGE_COPPER) { - set = AT803X_BT_BX_REG_SEL; - mask = 0; - } else { - set = 0; - mask = AT803X_BT_BX_REG_SEL; - } - - return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set); -} - -static int at803x_read_page(struct phy_device *phydev) -{ - int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG); - - if (ccr < 0) - return ccr; - - if (ccr & AT803X_BT_BX_REG_SEL) - return AT803X_PAGE_COPPER; - - return AT803X_PAGE_FIBER; -} - -static int at803x_enable_rx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, - AT803X_DEBUG_RX_CLK_DLY_EN); -} - -static int at803x_enable_tx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, - AT803X_DEBUG_TX_CLK_DLY_EN); -} - -static int at803x_disable_rx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - AT803X_DEBUG_RX_CLK_DLY_EN, 0); -} - -static int at803x_disable_tx_delay(struct phy_device *phydev) -{ - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, - AT803X_DEBUG_TX_CLK_DLY_EN, 0); -} - -/* save relevant PHY registers to private copy */ -static void at803x_context_save(struct phy_device *phydev, - struct at803x_context *context) -{ - context->bmcr = phy_read(phydev, MII_BMCR); - context->advertise = phy_read(phydev, MII_ADVERTISE); - context->control1000 = phy_read(phydev, MII_CTRL1000); - context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); - context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); - context->led_control = phy_read(phydev, AT803X_LED_CONTROL); -} - -/* restore relevant PHY registers from private copy */ -static void at803x_context_restore(struct phy_device *phydev, - const struct at803x_context *context) -{ - phy_write(phydev, MII_BMCR, context->bmcr); - phy_write(phydev, MII_ADVERTISE, context->advertise); - phy_write(phydev, MII_CTRL1000, context->control1000); - phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); - phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); - phy_write(phydev, AT803X_LED_CONTROL, context->led_control); -} - -static int at803x_set_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int ret, irq_enabled; - - if (wol->wolopts & WAKE_MAGIC) { - struct net_device *ndev = phydev->attached_dev; - const u8 *mac; - unsigned int i; - static const unsigned int offsets[] = { - AT803X_LOC_MAC_ADDR_32_47_OFFSET, - AT803X_LOC_MAC_ADDR_16_31_OFFSET, - AT803X_LOC_MAC_ADDR_0_15_OFFSET, - }; - - if (!ndev) - return -ENODEV; - - mac = (const u8 *)ndev->dev_addr; - - if (!is_valid_ether_addr(mac)) - return -EINVAL; - - for (i = 0; i < 3; i++) - phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], - mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); - - /* Enable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); - if (ret) - return ret; - } else { - /* Disable WOL interrupt */ - ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); - if (ret) - return ret; - } - - /* Clear WOL status */ - ret = phy_read(phydev, AT803X_INTR_STATUS); - if (ret < 0) - return ret; - - /* Check if there are other interrupts except for WOL triggered when PHY is - * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can - * be passed up to the interrupt PIN. - */ - irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (irq_enabled < 0) - return irq_enabled; - - irq_enabled &= ~AT803X_INTR_ENABLE_WOL; - if (ret & irq_enabled && !phy_polling_mode(phydev)) - phy_trigger_machine(phydev); - - return 0; -} - -static void at803x_get_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int value; - - wol->supported = WAKE_MAGIC; - wol->wolopts = 0; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - if (value < 0) - return; - - if (value & AT803X_INTR_ENABLE_WOL) - wol->wolopts |= WAKE_MAGIC; -} - -static int qca83xx_get_sset_count(struct phy_device *phydev) -{ - return ARRAY_SIZE(qca83xx_hw_stats); -} - -static void qca83xx_get_strings(struct phy_device *phydev, u8 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) { - strscpy(data + i * ETH_GSTRING_LEN, - qca83xx_hw_stats[i].string, ETH_GSTRING_LEN); - } -} - -static u64 qca83xx_get_stat(struct phy_device *phydev, int i) -{ - struct at803x_hw_stat stat = qca83xx_hw_stats[i]; - struct at803x_priv *priv = phydev->priv; - int val; - u64 ret; - - if (stat.access_type == MMD) - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); - else - val = phy_read(phydev, stat.reg); - - if (val < 0) { - ret = U64_MAX; - } else { - val = val & stat.mask; - priv->stats[i] += val; - ret = priv->stats[i]; - } - - return ret; -} - -static void qca83xx_get_stats(struct phy_device *phydev, - struct ethtool_stats *stats, u64 *data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) - data[i] = qca83xx_get_stat(phydev, i); -} - -static int at803x_suspend(struct phy_device *phydev) -{ - int value; - int wol_enabled; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - wol_enabled = value & AT803X_INTR_ENABLE_WOL; - - if (wol_enabled) - value = BMCR_ISOLATE; - else - value = BMCR_PDOWN; - - phy_modify(phydev, MII_BMCR, 0, value); - - return 0; -} - -static int at803x_resume(struct phy_device *phydev) -{ - return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); -} - -static int at803x_parse_dt(struct phy_device *phydev) -{ - struct device_node *node = phydev->mdio.dev.of_node; - struct at803x_priv *priv = phydev->priv; - u32 freq, strength, tw; - unsigned int sel; - int ret; - - if (!IS_ENABLED(CONFIG_OF_MDIO)) - return 0; - - if (of_property_read_bool(node, "qca,disable-smarteee")) - priv->flags |= AT803X_DISABLE_SMARTEEE; - - if (of_property_read_bool(node, "qca,disable-hibernation-mode")) - priv->flags |= AT803X_DISABLE_HIBERNATION_MODE; - - if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) { - if (!tw || tw > 255) { - phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n"); - return -EINVAL; - } - priv->smarteee_lpi_tw_1g = tw; - } - - if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) { - if (!tw || tw > 255) { - phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n"); - return -EINVAL; - } - priv->smarteee_lpi_tw_100m = tw; - } - - ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); - if (!ret) { - switch (freq) { - case 25000000: - sel = AT803X_CLK_OUT_25MHZ_XTAL; - break; - case 50000000: - sel = AT803X_CLK_OUT_50MHZ_PLL; - break; - case 62500000: - sel = AT803X_CLK_OUT_62_5MHZ_PLL; - break; - case 125000000: - sel = AT803X_CLK_OUT_125MHZ_PLL; - break; - default: - phydev_err(phydev, "invalid qca,clk-out-frequency\n"); - return -EINVAL; - } - - priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel); - priv->clk_25m_mask |= AT803X_CLK_OUT_MASK; - } - - ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); - if (!ret) { - priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; - switch (strength) { - case AR803X_STRENGTH_FULL: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; - break; - case AR803X_STRENGTH_HALF: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; - break; - case AR803X_STRENGTH_QUARTER: - priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; - break; - default: - phydev_err(phydev, "invalid qca,clk-out-strength\n"); - return -EINVAL; - } - } - - return 0; -} - -static int at803x_probe(struct phy_device *phydev) -{ - struct device *dev = &phydev->mdio.dev; - struct at803x_priv *priv; - int ret; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - phydev->priv = priv; - - ret = at803x_parse_dt(phydev); - if (ret) - return ret; - - return 0; -} - -static int at803x_get_features(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int err; - - err = genphy_read_abilities(phydev); - if (err) - return err; - - if (phydev->drv->phy_id != ATH8031_PHY_ID) - return 0; - - /* AR8031/AR8033 have different status registers - * for copper and fiber operation. However, the - * extended status register is the same for both - * operation modes. - * - * As a result of that, ESTATUS_1000_XFULL is set - * to 1 even when operating in copper TP mode. - * - * Remove this mode from the supported link modes - * when not operating in 1000BaseX mode. - */ - if (!priv->is_1000basex) - linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, - phydev->supported); - - return 0; -} - -static int at803x_smarteee_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - u16 mask = 0, val = 0; - int ret; - - if (priv->flags & AT803X_DISABLE_SMARTEEE) - return phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_MMD3_SMARTEEE_CTL3, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0); - - if (priv->smarteee_lpi_tw_1g) { - mask |= 0xff00; - val |= priv->smarteee_lpi_tw_1g << 8; - } - if (priv->smarteee_lpi_tw_100m) { - mask |= 0x00ff; - val |= priv->smarteee_lpi_tw_100m; - } - if (!mask) - return 0; - - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1, - mask, val); - if (ret) - return ret; - - return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, - AT803X_MMD3_SMARTEEE_CTL3_LPI_EN); -} - -static int at803x_clk_out_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - if (!priv->clk_25m_mask) - return 0; - - return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, - priv->clk_25m_mask, priv->clk_25m_reg); -} - -static int at8031_pll_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - /* The default after hardware reset is PLL OFF. After a soft reset, the - * values are retained. - */ - if (priv->flags & AT803X_KEEP_PLL_ENABLED) - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - 0, AT803X_DEBUG_PLL_ON); - else - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - AT803X_DEBUG_PLL_ON, 0); -} - -static int at803x_hibernation_mode_config(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - /* The default after hardware reset is hibernation mode enabled. After - * software reset, the value is retained. - */ - if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE)) - return 0; - - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, - AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0); -} - -static int at803x_config_init(struct phy_device *phydev) -{ - int ret; - - /* The RX and TX delay default is: - * after HW reset: RX delay enabled and TX delay disabled - * after SW reset: RX delay enabled, while TX delay retains the - * value before reset. - */ - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) - ret = at803x_enable_rx_delay(phydev); - else - ret = at803x_disable_rx_delay(phydev); - if (ret < 0) - return ret; - - if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || - phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) - ret = at803x_enable_tx_delay(phydev); - else - ret = at803x_disable_tx_delay(phydev); - if (ret < 0) - return ret; - - ret = at803x_smarteee_config(phydev); - if (ret < 0) - return ret; - - ret = at803x_clk_out_config(phydev); - if (ret < 0) - return ret; - - ret = at803x_hibernation_mode_config(phydev); - if (ret < 0) - return ret; - - /* Ar803x extended next page bit is enabled by default. Cisco - * multigig switches read this bit and attempt to negotiate 10Gbps - * rates even if the next page bit is disabled. This is incorrect - * behaviour but we still need to accommodate it. XNP is only needed - * for 10Gbps support, so disable XNP. - */ - return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); -} - -static int at803x_ack_interrupt(struct phy_device *phydev) -{ - int err; - - err = phy_read(phydev, AT803X_INTR_STATUS); - - return (err < 0) ? err : 0; -} - -static int at803x_config_intr(struct phy_device *phydev) -{ - int err; - int value; - - value = phy_read(phydev, AT803X_INTR_ENABLE); - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - if (err) - return err; - - value |= AT803X_INTR_ENABLE_AUTONEG_ERR; - value |= AT803X_INTR_ENABLE_SPEED_CHANGED; - value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; - value |= AT803X_INTR_ENABLE_LINK_FAIL; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS; - - err = phy_write(phydev, AT803X_INTR_ENABLE, value); - } else { - err = phy_write(phydev, AT803X_INTR_ENABLE, 0); - if (err) - return err; - - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - } - - return err; -} - -static irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) -{ - int irq_status, int_enabled; - - irq_status = phy_read(phydev, AT803X_INTR_STATUS); - if (irq_status < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* Read the current enabled interrupts */ - int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); - if (int_enabled < 0) { - phy_error(phydev); - return IRQ_NONE; - } - - /* See if this was one of our enabled interrupts */ - if (!(irq_status & int_enabled)) - return IRQ_NONE; - - phy_trigger_machine(phydev); - - return IRQ_HANDLED; -} - -static void at803x_link_change_notify(struct phy_device *phydev) -{ - /* - * Conduct a hardware reset for AT8030 every time a link loss is - * signalled. This is necessary to circumvent a hardware bug that - * occurs when the cable is unplugged while TX packets are pending - * in the FIFO. In such cases, the FIFO enters an error mode it - * cannot recover from by software. - */ - if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) { - struct at803x_context context; - - at803x_context_save(phydev, &context); - - phy_device_reset(phydev, 1); - usleep_range(1000, 2000); - phy_device_reset(phydev, 0); - usleep_range(1000, 2000); - - at803x_context_restore(phydev, &context); - - phydev_dbg(phydev, "%s(): phy was reset\n", __func__); - } -} - -static int at803x_read_specific_status(struct phy_device *phydev, - struct at803x_ss_mask ss_mask) -{ - int ss; - - /* Read the AT8035 PHY-Specific Status register, which indicates the - * speed and duplex that the PHY is actually using, irrespective of - * whether we are in autoneg mode or not. - */ - ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); - if (ss < 0) - return ss; - - if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { - int sfc, speed; - - sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); - if (sfc < 0) - return sfc; - - speed = ss & ss_mask.speed_mask; - speed >>= ss_mask.speed_shift; - - switch (speed) { - case AT803X_SS_SPEED_10: - phydev->speed = SPEED_10; - break; - case AT803X_SS_SPEED_100: - phydev->speed = SPEED_100; - break; - case AT803X_SS_SPEED_1000: - phydev->speed = SPEED_1000; - break; - case QCA808X_SS_SPEED_2500: - phydev->speed = SPEED_2500; - break; - } - if (ss & AT803X_SS_DUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - if (ss & AT803X_SS_MDIX) - phydev->mdix = ETH_TP_MDI_X; - else - phydev->mdix = ETH_TP_MDI; - - switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { - case AT803X_SFC_MANUAL_MDI: - phydev->mdix_ctrl = ETH_TP_MDI; - break; - case AT803X_SFC_MANUAL_MDIX: - phydev->mdix_ctrl = ETH_TP_MDI_X; - break; - case AT803X_SFC_AUTOMATIC_CROSSOVER: - phydev->mdix_ctrl = ETH_TP_MDI_AUTO; - break; - } - } - - return 0; -} - -static int at803x_read_status(struct phy_device *phydev) -{ - struct at803x_ss_mask ss_mask = { 0 }; - int err, old_link = phydev->link; - - /* Update the link, but return if there was an error */ - err = genphy_update_link(phydev); - if (err) - return err; - - /* why bother the PHY if nothing can have changed */ - if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) - return 0; - - phydev->speed = SPEED_UNKNOWN; - phydev->duplex = DUPLEX_UNKNOWN; - phydev->pause = 0; - phydev->asym_pause = 0; - - err = genphy_read_lpa(phydev); - if (err < 0) - return err; - - ss_mask.speed_mask = AT803X_SS_SPEED_MASK; - ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); - err = at803x_read_specific_status(phydev, ss_mask); - if (err < 0) - return err; - - if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) - phy_resolve_aneg_pause(phydev); - - return 0; -} - -static int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) -{ - u16 val; - - switch (ctrl) { - case ETH_TP_MDI: - val = AT803X_SFC_MANUAL_MDI; - break; - case ETH_TP_MDI_X: - val = AT803X_SFC_MANUAL_MDIX; - break; - case ETH_TP_MDI_AUTO: - val = AT803X_SFC_AUTOMATIC_CROSSOVER; - break; - default: - return 0; - } - - return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, - AT803X_SFC_MDI_CROSSOVER_MODE_M, - FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); -} - -static int at803x_prepare_config_aneg(struct phy_device *phydev) -{ - int ret; - - ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); - if (ret < 0) - return ret; - - /* Changes of the midx bits are disruptive to the normal operation; - * therefore any changes to these registers must be followed by a - * software reset to take effect. - */ - if (ret == 1) { - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - } - - return 0; -} - -static int at803x_config_aneg(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int ret; - - ret = at803x_prepare_config_aneg(phydev); - if (ret) - return ret; - - if (priv->is_1000basex) - return genphy_c37_config_aneg(phydev); - - return genphy_config_aneg(phydev); -} - -static int at803x_get_downshift(struct phy_device *phydev, u8 *d) -{ - int val; - - val = phy_read(phydev, AT803X_SMART_SPEED); - if (val < 0) - return val; - - if (val & AT803X_SMART_SPEED_ENABLE) - *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; - else - *d = DOWNSHIFT_DEV_DISABLE; - - return 0; -} - -static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) -{ - u16 mask, set; - int ret; - - switch (cnt) { - case DOWNSHIFT_DEV_DEFAULT_COUNT: - cnt = AT803X_DEFAULT_DOWNSHIFT; - fallthrough; - case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: - set = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER | - FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); - mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; - break; - case DOWNSHIFT_DEV_DISABLE: - set = 0; - mask = AT803X_SMART_SPEED_ENABLE | - AT803X_SMART_SPEED_BYPASS_TIMER; - break; - default: - return -EINVAL; - } - - ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); - - /* After changing the smart speed settings, we need to perform a - * software reset, use phy_init_hw() to make sure we set the - * reapply any values which might got lost during software reset. - */ - if (ret == 1) - ret = phy_init_hw(phydev); - - return ret; -} - -static int at803x_get_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_get_downshift(phydev, data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_set_tunable(struct phy_device *phydev, - struct ethtool_tunable *tuna, const void *data) -{ - switch (tuna->id) { - case ETHTOOL_PHY_DOWNSHIFT: - return at803x_set_downshift(phydev, *(const u8 *)data); - default: - return -EOPNOTSUPP; - } -} - -static int at803x_cable_test_result_trans(u16 status) -{ - switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { - case AT803X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case AT803X_CDT_STATUS_STAT_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case AT803X_CDT_STATUS_STAT_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case AT803X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static bool at803x_cdt_test_failed(u16 status) -{ - return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == - AT803X_CDT_STATUS_STAT_FAIL; -} - -static bool at803x_cdt_fault_length_valid(u16 status) -{ - switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { - case AT803X_CDT_STATUS_STAT_OPEN: - case AT803X_CDT_STATUS_STAT_SHORT: - return true; - } - return false; -} - -static int at803x_cdt_fault_length(int dt) -{ - /* According to the datasheet the distance to the fault is - * DELTA_TIME * 0.824 meters. - * - * The author suspect the correct formula is: - * - * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 - * - * where c is the speed of light, VF is the velocity factor of - * the twisted pair cable, 125MHz the counter frequency and - * we need to divide by 2 because the hardware will measure the - * round trip time to the fault and back to the PHY. - * - * With a VF of 0.69 we get the factor 0.824 mentioned in the - * datasheet. - */ - return (dt * 824) / 10; -} - -static int at803x_cdt_start(struct phy_device *phydev, - u32 cdt_start) -{ - return phy_write(phydev, AT803X_CDT, cdt_start); -} - -static int at803x_cdt_wait_for_completion(struct phy_device *phydev, - u32 cdt_en) -{ - int val, ret; - - /* One test run takes about 25ms */ - ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, - !(val & cdt_en), - 30000, 100000, true); - - return ret < 0 ? ret : 0; -} - -static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) -{ - static const int ethtool_pair[] = { - ETHTOOL_A_CABLE_PAIR_A, - ETHTOOL_A_CABLE_PAIR_B, - ETHTOOL_A_CABLE_PAIR_C, - ETHTOOL_A_CABLE_PAIR_D, - }; - int ret, val; - - val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | - AT803X_CDT_ENABLE_TEST; - ret = at803x_cdt_start(phydev, val); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST); - if (ret) - return ret; - - val = phy_read(phydev, AT803X_CDT_STATUS); - if (val < 0) - return val; - - if (at803x_cdt_test_failed(val)) - return 0; - - ethnl_cable_test_result(phydev, ethtool_pair[pair], - at803x_cable_test_result_trans(val)); - - if (at803x_cdt_fault_length_valid(val)) { - val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val); - ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], - at803x_cdt_fault_length(val)); - } - - return 1; -} - -static int at803x_cable_test_get_status(struct phy_device *phydev, - bool *finished, unsigned long pair_mask) -{ - int retries = 20; - int pair, ret; - - *finished = false; - - /* According to the datasheet the CDT can be performed when - * there is no link partner or when the link partner is - * auto-negotiating. Starting the test will restart the AN - * automatically. It seems that doing this repeatedly we will - * get a slot where our link partner won't disturb our - * measurement. - */ - while (pair_mask && retries--) { - for_each_set_bit(pair, &pair_mask, 4) { - ret = at803x_cable_test_one_pair(phydev, pair); - if (ret < 0) - return ret; - if (ret) - clear_bit(pair, &pair_mask); - } - if (pair_mask) - msleep(250); - } - - *finished = true; - - return 0; -} - -static void at803x_cable_test_autoneg(struct phy_device *phydev) -{ - /* Enable auto-negotiation, but advertise no capabilities, no link - * will be established. A restart of the auto-negotiation is not - * required, because the cable test will automatically break the link. - */ - phy_write(phydev, MII_BMCR, BMCR_ANENABLE); - phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); -} - -static int at803x_cable_test_start(struct phy_device *phydev) -{ - at803x_cable_test_autoneg(phydev); - /* we do all the (time consuming) work later */ - return 0; -} - -static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, - unsigned int selector) -{ - struct phy_device *phydev = rdev_get_drvdata(rdev); - - if (selector) - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - 0, AT803X_DEBUG_RGMII_1V8); - else - return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, - AT803X_DEBUG_RGMII_1V8, 0); -} - -static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) -{ - struct phy_device *phydev = rdev_get_drvdata(rdev); - int val; - - val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); - if (val < 0) - return val; - - return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; -} - -static const struct regulator_ops vddio_regulator_ops = { - .list_voltage = regulator_list_voltage_table, - .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel, - .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel, -}; - -static const unsigned int vddio_voltage_table[] = { - 1500000, - 1800000, -}; - -static const struct regulator_desc vddio_desc = { - .name = "vddio", - .of_match = of_match_ptr("vddio-regulator"), - .n_voltages = ARRAY_SIZE(vddio_voltage_table), - .volt_table = vddio_voltage_table, - .ops = &vddio_regulator_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, -}; - -static const struct regulator_ops vddh_regulator_ops = { -}; - -static const struct regulator_desc vddh_desc = { - .name = "vddh", - .of_match = of_match_ptr("vddh-regulator"), - .n_voltages = 1, - .fixed_uV = 2500000, - .ops = &vddh_regulator_ops, - .type = REGULATOR_VOLTAGE, - .owner = THIS_MODULE, -}; - -static int at8031_register_regulators(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - struct device *dev = &phydev->mdio.dev; - struct regulator_config config = { }; - - config.dev = dev; - config.driver_data = phydev; - - priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); - if (IS_ERR(priv->vddio_rdev)) { - phydev_err(phydev, "failed to register VDDIO regulator\n"); - return PTR_ERR(priv->vddio_rdev); - } - - priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); - if (IS_ERR(priv->vddh_rdev)) { - phydev_err(phydev, "failed to register VDDH regulator\n"); - return PTR_ERR(priv->vddh_rdev); - } - - return 0; -} - -static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) -{ - struct phy_device *phydev = upstream; - __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); - __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); - DECLARE_PHY_INTERFACE_MASK(interfaces); - phy_interface_t iface; - - linkmode_zero(phy_support); - phylink_set(phy_support, 1000baseX_Full); - phylink_set(phy_support, 1000baseT_Full); - phylink_set(phy_support, Autoneg); - phylink_set(phy_support, Pause); - phylink_set(phy_support, Asym_Pause); - - linkmode_zero(sfp_support); - sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces); - /* Some modules support 10G modes as well as others we support. - * Mask out non-supported modes so the correct interface is picked. - */ - linkmode_and(sfp_support, phy_support, sfp_support); - - if (linkmode_empty(sfp_support)) { - dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); - return -EINVAL; - } - - iface = sfp_select_interface(phydev->sfp_bus, sfp_support); - - /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes - * interface for use with SFP modules. - * However, some copper modules detected as having a preferred SGMII - * interface do default to and function in 1000Base-X mode, so just - * print a warning and allow such modules, as they may have some chance - * of working. - */ - if (iface == PHY_INTERFACE_MODE_SGMII) - dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); - else if (iface != PHY_INTERFACE_MODE_1000BASEX) - return -EINVAL; - - return 0; -} - -static const struct sfp_upstream_ops at8031_sfp_ops = { - .attach = phy_sfp_attach, - .detach = phy_sfp_detach, - .module_insert = at8031_sfp_insert, -}; - -static int at8031_parse_dt(struct phy_device *phydev) -{ - struct device_node *node = phydev->mdio.dev.of_node; - struct at803x_priv *priv = phydev->priv; - int ret; - - if (of_property_read_bool(node, "qca,keep-pll-enabled")) - priv->flags |= AT803X_KEEP_PLL_ENABLED; - - ret = at8031_register_regulators(phydev); - if (ret < 0) - return ret; - - ret = devm_regulator_get_enable_optional(&phydev->mdio.dev, - "vddio"); - if (ret) { - phydev_err(phydev, "failed to get VDDIO regulator\n"); - return ret; - } - - /* Only AR8031/8033 support 1000Base-X for SFP modules */ - return phy_sfp_probe(phydev, &at8031_sfp_ops); -} - -static int at8031_probe(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int mode_cfg; - int ccr; - int ret; - - ret = at803x_probe(phydev); - if (ret) - return ret; - - /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping - * options. - */ - ret = at8031_parse_dt(phydev); - if (ret) - return ret; - - ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); - if (ccr < 0) - return ccr; - mode_cfg = ccr & AT803X_MODE_CFG_MASK; - - switch (mode_cfg) { - case AT803X_MODE_CFG_BX1000_RGMII_50OHM: - case AT803X_MODE_CFG_BX1000_RGMII_75OHM: - priv->is_1000basex = true; - fallthrough; - case AT803X_MODE_CFG_FX100_RGMII_50OHM: - case AT803X_MODE_CFG_FX100_RGMII_75OHM: - priv->is_fiber = true; - break; - } - - /* Disable WoL in 1588 register which is enabled - * by default - */ - return phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - AT803X_WOL_EN, 0); -} - -static int at8031_config_init(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int ret; - - /* Some bootloaders leave the fiber page selected. - * Switch to the appropriate page (fiber or copper), as otherwise we - * read the PHY capabilities from the wrong page. - */ - phy_lock_mdio_bus(phydev); - ret = at803x_write_page(phydev, - priv->is_fiber ? AT803X_PAGE_FIBER : - AT803X_PAGE_COPPER); - phy_unlock_mdio_bus(phydev); - if (ret) - return ret; - - ret = at8031_pll_config(phydev); - if (ret < 0) - return ret; - - return at803x_config_init(phydev); -} - -static int at8031_set_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol) -{ - int ret; - - /* First setup MAC address and enable WOL interrupt */ - ret = at803x_set_wol(phydev, wol); - if (ret) - return ret; - - if (wol->wolopts & WAKE_MAGIC) - /* Enable WOL function for 1588 */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - 0, AT803X_WOL_EN); - else - /* Disable WoL function for 1588 */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, - AT803X_PHY_MMD3_WOL_CTRL, - AT803X_WOL_EN, 0); - - return ret; -} - -static int at8031_config_intr(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - int err, value = 0; - - if (phydev->interrupts == PHY_INTERRUPT_ENABLED && - priv->is_fiber) { - /* Clear any pending interrupts */ - err = at803x_ack_interrupt(phydev); - if (err) - return err; - - value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; - value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; - - err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value); - if (err) - return err; - } - - return at803x_config_intr(phydev); -} - -/* AR8031 and AR8033 share the same read status logic */ -static int at8031_read_status(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - if (priv->is_1000basex) - return genphy_c37_read_status(phydev); - - return at803x_read_status(phydev); -} - -/* AR8031 and AR8035 share the same cable test get status reg */ -static int at8031_cable_test_get_status(struct phy_device *phydev, - bool *finished) -{ - return at803x_cable_test_get_status(phydev, finished, 0xf); -} - -/* AR8031 and AR8035 share the same cable test start logic */ -static int at8031_cable_test_start(struct phy_device *phydev) -{ - at803x_cable_test_autoneg(phydev); - phy_write(phydev, MII_CTRL1000, 0); - /* we do all the (time consuming) work later */ - return 0; -} - -/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */ -static int at8032_cable_test_get_status(struct phy_device *phydev, - bool *finished) -{ - return at803x_cable_test_get_status(phydev, finished, 0x3); -} - -static int at8035_parse_dt(struct phy_device *phydev) -{ - struct at803x_priv *priv = phydev->priv; - - /* Mask is set by the generic at803x_parse_dt - * if property is set. Assume property is set - * with the mask not zero. - */ - if (priv->clk_25m_mask) { - /* Fixup for the AR8030/AR8035. This chip has another mask and - * doesn't support the DSP reference. Eg. the lowest bit of the - * mask. The upper two bits select the same frequencies. Mask - * the lowest bit here. - * - * Warning: - * There was no datasheet for the AR8030 available so this is - * just a guess. But the AR8035 is listed as pin compatible - * to the AR8030 so there might be a good chance it works on - * the AR8030 too. - */ - priv->clk_25m_reg &= AT8035_CLK_OUT_MASK; - priv->clk_25m_mask &= AT8035_CLK_OUT_MASK; - } - - return 0; -} - -/* AR8030 and AR8035 shared the same special mask for clk_25m */ -static int at8035_probe(struct phy_device *phydev) -{ - int ret; - - ret = at803x_probe(phydev); - if (ret) - return ret; - - return at8035_parse_dt(phydev); -} - -static int qca83xx_config_init(struct phy_device *phydev) -{ - u8 switch_revision; - - switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; - - switch (switch_revision) { - case 1: - /* For 100M waveform */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); - /* Turn on Gigabit clock */ - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); - break; - - case 2: - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); - fallthrough; - case 4: - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); - at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); - break; - } - - /* Following original QCA sourcecode set port to prefer master */ - phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); - - return 0; -} - -static int qca8327_config_init(struct phy_device *phydev) -{ - /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. - * Disable on init and enable only with 100m speed following - * qca original source code. - */ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - - return qca83xx_config_init(phydev); -} - -static void qca83xx_link_change_notify(struct phy_device *phydev) -{ - /* Set DAC Amplitude adjustment to +6% for 100m on link running */ - if (phydev->state == PHY_RUNNING) { - if (phydev->speed == SPEED_100) - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, - QCA8327_DEBUG_MANU_CTRL_EN); - } else { - /* Reset DAC Amplitude adjustment */ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, - QCA8327_DEBUG_MANU_CTRL_EN, 0); - } -} - -static int qca83xx_resume(struct phy_device *phydev) -{ - int ret, val; - - /* Skip reset if not suspended */ - if (!phydev->suspended) - return 0; - - /* Reinit the port, reset values set by suspend */ - qca83xx_config_init(phydev); - - /* Reset the port on port resume */ - phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - - /* On resume from suspend the switch execute a reset and - * restart auto-negotiation. Wait for reset to complete. - */ - ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), - 50000, 600000, true); - if (ret) - return ret; - - usleep_range(1000, 2000); - - return 0; -} - -static int qca83xx_suspend(struct phy_device *phydev) -{ - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, - AT803X_DEBUG_GATE_CLK_IN1000, 0); - - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, - AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | - AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); - - return 0; -} - -static int qca8337_suspend(struct phy_device *phydev) -{ - /* Only QCA8337 support actual suspend. */ - genphy_suspend(phydev); - - return qca83xx_suspend(phydev); -} - -static int qca8327_suspend(struct phy_device *phydev) -{ - u16 mask = 0; - - /* QCA8327 cause port unreliability when phy suspend - * is set. - */ - mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); - phy_modify(phydev, MII_BMCR, mask, 0); - - return qca83xx_suspend(phydev); -} - -static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) -{ - int ret; - - /* Enable fast retrain */ - ret = genphy_c45_fast_retrain(phydev, true); - if (ret) - return ret; - - phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, - QCA808X_TOP_OPTION1_DATA); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, - QCA808X_MSE_THRESHOLD_20DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, - QCA808X_MSE_THRESHOLD_17DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, - QCA808X_MSE_THRESHOLD_27DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, - QCA808X_MSE_THRESHOLD_28DB_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, - QCA808X_MMD3_DEBUG_1_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, - QCA808X_MMD3_DEBUG_4_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, - QCA808X_MMD3_DEBUG_5_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, - QCA808X_MMD3_DEBUG_3_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, - QCA808X_MMD3_DEBUG_6_VALUE); - phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, - QCA808X_MMD3_DEBUG_2_VALUE); - - return 0; -} - -static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) -{ - u16 seed_value; - - if (!enable) - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); - - seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, - QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, - FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | - QCA808X_MASTER_SLAVE_SEED_ENABLE); -} - -static bool qca808x_is_prefer_master(struct phy_device *phydev) -{ - return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || - (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); -} - -static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) -{ - return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); -} - -static int qca808x_config_init(struct phy_device *phydev) -{ - int ret; - - /* Active adc&vga on 802.3az for the link 1000M and 100M */ - ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, - QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); - if (ret) - return ret; - - /* Adjust the threshold on 802.3az for the link 1000M */ - ret = phy_write_mmd(phydev, MDIO_MMD_PCS, - QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, - QCA808X_MMD3_AZ_TRAINING_VAL); - if (ret) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - /* Config the fast retrain for the link 2500M */ - ret = qca808x_phy_fast_retrain_config(phydev); - if (ret) - return ret; - - ret = genphy_read_master_slave(phydev); - if (ret < 0) - return ret; - - if (!qca808x_is_prefer_master(phydev)) { - /* Enable seed and configure lower ramdom seed to make phy - * linked as slave mode. - */ - ret = qca808x_phy_ms_seed_enable(phydev, true); - if (ret) - return ret; - } - } - - /* Configure adc threshold as 100mv for the link 10M */ - return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, - QCA808X_ADC_THRESHOLD_MASK, - QCA808X_ADC_THRESHOLD_100MV); -} - -static int qca808x_read_status(struct phy_device *phydev) -{ - struct at803x_ss_mask ss_mask = { 0 }; - int ret; - - ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); - if (ret < 0) - return ret; - - linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, - ret & MDIO_AN_10GBT_STAT_LP2_5G); - - ret = genphy_read_status(phydev); - if (ret) - return ret; - - /* qca8081 takes the different bits for speed value from at803x */ - ss_mask.speed_mask = QCA808X_SS_SPEED_MASK; - ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK); - ret = at803x_read_specific_status(phydev, ss_mask); - if (ret < 0) - return ret; - - if (phydev->link) { - if (phydev->speed == SPEED_2500) - phydev->interface = PHY_INTERFACE_MODE_2500BASEX; - else - phydev->interface = PHY_INTERFACE_MODE_SGMII; - } else { - /* generate seed as a lower random value to make PHY linked as SLAVE easily, - * except for master/slave configuration fault detected or the master mode - * preferred. - * - * the reason for not putting this code into the function link_change_notify is - * the corner case where the link partner is also the qca8081 PHY and the seed - * value is configured as the same value, the link can't be up and no link change - * occurs. - */ - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { - if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || - qca808x_is_prefer_master(phydev)) { - qca808x_phy_ms_seed_enable(phydev, false); - } else { - qca808x_phy_ms_seed_enable(phydev, true); - } - } - } - - return 0; -} - -static int qca808x_soft_reset(struct phy_device *phydev) -{ - int ret; - - ret = genphy_soft_reset(phydev); - if (ret < 0) - return ret; - - if (qca808x_has_fast_retrain_or_slave_seed(phydev)) - ret = qca808x_phy_ms_seed_enable(phydev, true); - - return ret; -} - -static bool qca808x_cdt_fault_length_valid(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return true; - default: - return false; - } -} - -static int qca808x_cable_test_result_trans(int cdt_code) -{ - switch (cdt_code) { - case QCA808X_CDT_STATUS_STAT_NORMAL: - return ETHTOOL_A_CABLE_RESULT_CODE_OK; - case QCA808X_CDT_STATUS_STAT_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; - case QCA808X_CDT_STATUS_STAT_SAME_OPEN: - return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: - case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: - return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; - case QCA808X_CDT_STATUS_STAT_FAIL: - default: - return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; - } -} - -static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, - int result) -{ - int val; - u32 cdt_length_reg = 0; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; - break; - case ETHTOOL_A_CABLE_PAIR_B: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; - break; - case ETHTOOL_A_CABLE_PAIR_C: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; - break; - case ETHTOOL_A_CABLE_PAIR_D: - cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; - break; - default: - return -EINVAL; - } - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); - if (val < 0) - return val; - - if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); - else - val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); - - return at803x_cdt_fault_length(val); -} - -static int qca808x_cable_test_start(struct phy_device *phydev) -{ - int ret; - - /* perform CDT with the following configs: - * 1. disable hibernation. - * 2. force PHY working in MDI mode. - * 3. for PHY working in 1000BaseT. - * 4. configure the threshold. - */ - - ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); - if (ret < 0) - return ret; - - ret = at803x_config_mdix(phydev, ETH_TP_MDI); - if (ret < 0) - return ret; - - /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ - phydev->duplex = DUPLEX_FULL; - phydev->speed = SPEED_1000; - ret = genphy_c45_pma_setup_forced(phydev); - if (ret < 0) - return ret; - - ret = genphy_setup_forced(phydev); - if (ret < 0) - return ret; - - /* configure the thresholds for open, short, pair ok test */ - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); - phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); - - return 0; -} - -static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, - u16 status) -{ - int length, result; - u16 pair_code; - - switch (pair) { - case ETHTOOL_A_CABLE_PAIR_A: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); - break; - case ETHTOOL_A_CABLE_PAIR_B: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); - break; - case ETHTOOL_A_CABLE_PAIR_C: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); - break; - case ETHTOOL_A_CABLE_PAIR_D: - pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); - break; - default: - return -EINVAL; - } - - result = qca808x_cable_test_result_trans(pair_code); - ethnl_cable_test_result(phydev, pair, result); - - if (qca808x_cdt_fault_length_valid(pair_code)) { - length = qca808x_cdt_fault_length(phydev, pair, result); - ethnl_cable_test_fault_length(phydev, pair, length); - } - - return 0; -} - -static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) -{ - int ret, val; - - *finished = false; - - val = QCA808X_CDT_ENABLE_TEST | - QCA808X_CDT_LENGTH_UNIT; - ret = at803x_cdt_start(phydev, val); - if (ret) - return ret; - - ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); - if (ret) - return ret; - - val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); - if (val < 0) - return val; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); - if (ret) - return ret; - - ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); - if (ret) - return ret; - - *finished = true; - - return 0; -} - -static int qca808x_get_features(struct phy_device *phydev) -{ - int ret; - - ret = genphy_c45_pma_read_abilities(phydev); - if (ret) - return ret; - - /* The autoneg ability is not existed in bit3 of MMD7.1, - * but it is supported by qca808x PHY, so we add it here - * manually. - */ - linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); - - /* As for the qca8081 1G version chip, the 2500baseT ability is also - * existed in the bit0 of MMD1.21, we need to remove it manually if - * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. - */ - ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); - if (ret < 0) - return ret; - - if (QCA808X_PHY_CHIP_TYPE_1G & ret) - linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); - - return 0; -} - -static int qca808x_config_aneg(struct phy_device *phydev) -{ - int phy_ctrl = 0; - int ret; - - ret = at803x_prepare_config_aneg(phydev); - if (ret) - return ret; - - /* The reg MII_BMCR also needs to be configured for force mode, the - * genphy_config_aneg is also needed. - */ - if (phydev->autoneg == AUTONEG_DISABLE) - genphy_c45_pma_setup_forced(phydev); - - if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) - phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; - - ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, - MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); - if (ret < 0) - return ret; - - return __genphy_config_aneg(phydev, ret); -} - -static void qca808x_link_change_notify(struct phy_device *phydev) -{ - /* Assert interface sgmii fifo on link down, deassert it on link up, - * the interface device address is always phy address added by 1. - */ - mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, - MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, - QCA8081_PHY_FIFO_RSTN, - phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); -} - -static struct phy_driver at803x_driver[] = { -{ - /* Qualcomm Atheros AR8035 */ - PHY_ID_MATCH_EXACT(ATH8035_PHY_ID), - .name = "Qualcomm Atheros AR8035", - .flags = PHY_POLL_CABLE_TEST, - .probe = at8035_probe, - .config_aneg = at803x_config_aneg, - .config_init = at803x_config_init, - .soft_reset = genphy_soft_reset, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_GBIT_FEATURES */ - .read_status = at803x_read_status, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .cable_test_start = at8031_cable_test_start, - .cable_test_get_status = at8031_cable_test_get_status, -}, { - /* Qualcomm Atheros AR8030 */ - .phy_id = ATH8030_PHY_ID, - .name = "Qualcomm Atheros AR8030", - .phy_id_mask = AT8030_PHY_ID_MASK, - .probe = at8035_probe, - .config_init = at803x_config_init, - .link_change_notify = at803x_link_change_notify, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, -}, { - /* Qualcomm Atheros AR8031/AR8033 */ - PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), - .name = "Qualcomm Atheros AR8031/AR8033", - .flags = PHY_POLL_CABLE_TEST, - .probe = at8031_probe, - .config_init = at8031_config_init, - .config_aneg = at803x_config_aneg, - .soft_reset = genphy_soft_reset, - .set_wol = at8031_set_wol, - .get_wol = at803x_get_wol, - .suspend = at803x_suspend, - .resume = at803x_resume, - .read_page = at803x_read_page, - .write_page = at803x_write_page, - .get_features = at803x_get_features, - .read_status = at8031_read_status, - .config_intr = at8031_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .cable_test_start = at8031_cable_test_start, - .cable_test_get_status = at8031_cable_test_get_status, -}, { - /* Qualcomm Atheros AR8032 */ - PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), - .name = "Qualcomm Atheros AR8032", - .probe = at803x_probe, - .flags = PHY_POLL_CABLE_TEST, - .config_init = at803x_config_init, - .link_change_notify = at803x_link_change_notify, - .suspend = at803x_suspend, - .resume = at803x_resume, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at8032_cable_test_get_status, -}, { - /* ATHEROS AR9331 */ - PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), - .name = "Qualcomm Atheros AR9331 built-in PHY", - .probe = at803x_probe, - .suspend = at803x_suspend, - .resume = at803x_resume, - .flags = PHY_POLL_CABLE_TEST, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at8032_cable_test_get_status, - .read_status = at803x_read_status, - .soft_reset = genphy_soft_reset, - .config_aneg = at803x_config_aneg, -}, { - /* Qualcomm Atheros QCA9561 */ - PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), - .name = "Qualcomm Atheros QCA9561 built-in PHY", - .probe = at803x_probe, - .suspend = at803x_suspend, - .resume = at803x_resume, - .flags = PHY_POLL_CABLE_TEST, - /* PHY_BASIC_FEATURES */ - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .cable_test_start = at803x_cable_test_start, - .cable_test_get_status = at8032_cable_test_get_status, - .read_status = at803x_read_status, - .soft_reset = genphy_soft_reset, - .config_aneg = at803x_config_aneg, -}, { - /* QCA8337 */ - .phy_id = QCA8337_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8337 internal PHY", - /* PHY_GBIT_FEATURES */ - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca83xx_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8337_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-A from switch QCA8327-AL1A */ - .phy_id = QCA8327_A_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-A internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca8327_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8327_suspend, - .resume = qca83xx_resume, -}, { - /* QCA8327-B from switch QCA8327-BL1A */ - .phy_id = QCA8327_B_PHY_ID, - .phy_id_mask = QCA8K_PHY_ID_MASK, - .name = "Qualcomm Atheros 8327-B internal PHY", - /* PHY_GBIT_FEATURES */ - .link_change_notify = qca83xx_link_change_notify, - .probe = at803x_probe, - .flags = PHY_IS_INTERNAL, - .config_init = qca8327_config_init, - .soft_reset = genphy_soft_reset, - .get_sset_count = qca83xx_get_sset_count, - .get_strings = qca83xx_get_strings, - .get_stats = qca83xx_get_stats, - .suspend = qca8327_suspend, - .resume = qca83xx_resume, -}, { - /* Qualcomm QCA8081 */ - PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), - .name = "Qualcomm QCA8081", - .flags = PHY_POLL_CABLE_TEST, - .probe = at803x_probe, - .config_intr = at803x_config_intr, - .handle_interrupt = at803x_handle_interrupt, - .get_tunable = at803x_get_tunable, - .set_tunable = at803x_set_tunable, - .set_wol = at803x_set_wol, - .get_wol = at803x_get_wol, - .get_features = qca808x_get_features, - .config_aneg = qca808x_config_aneg, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_status = qca808x_read_status, - .config_init = qca808x_config_init, - .soft_reset = qca808x_soft_reset, - .cable_test_start = qca808x_cable_test_start, - .cable_test_get_status = qca808x_cable_test_get_status, - .link_change_notify = qca808x_link_change_notify, -}, }; - -module_phy_driver(at803x_driver); - -static struct mdio_device_id __maybe_unused atheros_tbl[] = { - { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, - { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, - { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, - { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, - { } -}; - -MODULE_DEVICE_TABLE(mdio, atheros_tbl); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index eba652a4c1d8..1faa22f58366 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1461,7 +1461,7 @@ static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs) static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs) { - struct ethtool_eee eee; + struct ethtool_keee eee; int val, ret; if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index dad720138baa..40bea9293ddd 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -154,11 +154,13 @@ #define PTP_CMD_CTL_PTP_LTC_STEP_SEC_ BIT(5) #define PTP_CMD_CTL_PTP_LTC_STEP_NSEC_ BIT(6) +#define PTP_CLOCK_SET_SEC_HI 0x0205 #define PTP_CLOCK_SET_SEC_MID 0x0206 #define PTP_CLOCK_SET_SEC_LO 0x0207 #define PTP_CLOCK_SET_NS_HI 0x0208 #define PTP_CLOCK_SET_NS_LO 0x0209 +#define PTP_CLOCK_READ_SEC_HI 0x0229 #define PTP_CLOCK_READ_SEC_MID 0x022A #define PTP_CLOCK_READ_SEC_LO 0x022B #define PTP_CLOCK_READ_NS_HI 0x022C @@ -2592,35 +2594,31 @@ static bool lan8814_rxtstamp(struct mii_timestamper *mii_ts, struct sk_buff *skb } static void lan8814_ptp_clock_set(struct phy_device *phydev, - u32 seconds, u32 nano_seconds) + time64_t sec, u32 nsec) { - u32 sec_low, sec_high, nsec_low, nsec_high; - - sec_low = seconds & 0xffff; - sec_high = (seconds >> 16) & 0xffff; - nsec_low = nano_seconds & 0xffff; - nsec_high = (nano_seconds >> 16) & 0x3fff; - - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_LO, sec_low); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_MID, sec_high); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_LO, nsec_low); - lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_HI, nsec_high); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_LO, lower_16_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_MID, upper_16_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_SEC_HI, upper_32_bits(sec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_LO, lower_16_bits(nsec)); + lanphy_write_page_reg(phydev, 4, PTP_CLOCK_SET_NS_HI, upper_16_bits(nsec)); lanphy_write_page_reg(phydev, 4, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_LOAD_); } static void lan8814_ptp_clock_get(struct phy_device *phydev, - u32 *seconds, u32 *nano_seconds) + time64_t *sec, u32 *nsec) { lanphy_write_page_reg(phydev, 4, PTP_CMD_CTL, PTP_CMD_CTL_PTP_CLOCK_READ_); - *seconds = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_MID); - *seconds = (*seconds << 16) | - lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_LO); + *sec = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_HI); + *sec <<= 16; + *sec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_MID); + *sec <<= 16; + *sec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_SEC_LO); - *nano_seconds = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_HI); - *nano_seconds = ((*nano_seconds & 0x3fff) << 16) | - lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_LO); + *nsec = lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_HI); + *nsec <<= 16; + *nsec |= lanphy_read_page_reg(phydev, 4, PTP_CLOCK_READ_NS_LO); } static int lan8814_ptpci_gettime64(struct ptp_clock_info *ptpci, @@ -2630,7 +2628,7 @@ static int lan8814_ptpci_gettime64(struct ptp_clock_info *ptpci, ptp_clock_info); struct phy_device *phydev = shared->phydev; u32 nano_seconds; - u32 seconds; + time64_t seconds; mutex_lock(&shared->shared_lock); lan8814_ptp_clock_get(phydev, &seconds, &nano_seconds); @@ -2660,38 +2658,37 @@ static void lan8814_ptp_clock_step(struct phy_device *phydev, { u32 nano_seconds_step; u64 abs_time_step_ns; - u32 unsigned_seconds; + time64_t set_seconds; u32 nano_seconds; u32 remainder; s32 seconds; if (time_step_ns > 15000000000LL) { /* convert to clock set */ - lan8814_ptp_clock_get(phydev, &unsigned_seconds, &nano_seconds); - unsigned_seconds += div_u64_rem(time_step_ns, 1000000000LL, - &remainder); + lan8814_ptp_clock_get(phydev, &set_seconds, &nano_seconds); + set_seconds += div_u64_rem(time_step_ns, 1000000000LL, + &remainder); nano_seconds += remainder; if (nano_seconds >= 1000000000) { - unsigned_seconds++; + set_seconds++; nano_seconds -= 1000000000; } - lan8814_ptp_clock_set(phydev, unsigned_seconds, nano_seconds); + lan8814_ptp_clock_set(phydev, set_seconds, nano_seconds); return; } else if (time_step_ns < -15000000000LL) { /* convert to clock set */ time_step_ns = -time_step_ns; - lan8814_ptp_clock_get(phydev, &unsigned_seconds, &nano_seconds); - unsigned_seconds -= div_u64_rem(time_step_ns, 1000000000LL, - &remainder); + lan8814_ptp_clock_get(phydev, &set_seconds, &nano_seconds); + set_seconds -= div_u64_rem(time_step_ns, 1000000000LL, + &remainder); nano_seconds_step = remainder; if (nano_seconds < nano_seconds_step) { - unsigned_seconds--; + set_seconds--; nano_seconds += 1000000000; } nano_seconds -= nano_seconds_step; - lan8814_ptp_clock_set(phydev, unsigned_seconds, - nano_seconds); + lan8814_ptp_clock_set(phydev, set_seconds, nano_seconds); return; } diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c index 747d14bf152c..46c87a903efd 100644 --- a/drivers/net/phy/phy-c45.c +++ b/drivers/net/phy/phy-c45.c @@ -1443,17 +1443,17 @@ EXPORT_SYMBOL(genphy_c45_eee_is_active); /** * genphy_c45_ethtool_get_eee - get EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it reports the Supported/Advertisement/LP Advertisement * capabilities. */ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, - struct ethtool_eee *data) + struct ethtool_keee *data) { __ETHTOOL_DECLARE_LINK_MODE_MASK(adv) = {}; __ETHTOOL_DECLARE_LINK_MODE_MASK(lp) = {}; - bool overflow = false, is_enabled; + bool is_enabled; int ret; ret = genphy_c45_eee_is_active(phydev, adv, lp, &is_enabled); @@ -1462,17 +1462,9 @@ int genphy_c45_ethtool_get_eee(struct phy_device *phydev, data->eee_enabled = is_enabled; data->eee_active = ret; - - if (!ethtool_convert_link_mode_to_legacy_u32(&data->supported, - phydev->supported_eee)) - overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->advertised, adv)) - overflow = true; - if (!ethtool_convert_link_mode_to_legacy_u32(&data->lp_advertised, lp)) - overflow = true; - - if (overflow) - phydev_warn(phydev, "Not all supported or advertised EEE link modes were passed to the user space\n"); + linkmode_copy(data->supported, phydev->supported_eee); + linkmode_copy(data->advertised, adv); + linkmode_copy(data->lp_advertised, lp); return 0; } @@ -1481,7 +1473,7 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); /** * genphy_c45_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: sets the Supported/Advertisement/LP Advertisement * capabilities. If eee_enabled is false, no links modes are @@ -1490,29 +1482,27 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee); * non-destructive way. */ int genphy_c45_ethtool_set_eee(struct phy_device *phydev, - struct ethtool_eee *data) + struct ethtool_keee *data) { int ret; if (data->eee_enabled) { - if (data->advertised) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(adv); + unsigned long *adv = data->advertised; - ethtool_convert_legacy_u32_to_link_mode(adv, - data->advertised); - linkmode_andnot(adv, adv, phydev->supported_eee); - if (!linkmode_empty(adv)) { + if (!linkmode_empty(adv)) { + __ETHTOOL_DECLARE_LINK_MODE_MASK(tmp); + bool unsupp; + + unsupp = linkmode_andnot(tmp, adv, phydev->supported_eee); + if (unsupp) { phydev_warn(phydev, "At least some EEE link modes are not supported.\n"); return -EINVAL; } - - ethtool_convert_legacy_u32_to_link_mode(phydev->advertising_eee, - data->advertised); } else { - linkmode_copy(phydev->advertising_eee, - phydev->supported_eee); + adv = phydev->supported_eee; } + linkmode_copy(phydev->advertising_eee, adv); phydev->eee_enabled = true; } else { phydev->eee_enabled = false; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3376e58e2b88..3b9531143be1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1632,12 +1632,12 @@ EXPORT_SYMBOL(phy_get_eee_err); /** * phy_ethtool_get_eee - get EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it reportes the Supported/Advertisement/LP Advertisement * capabilities. */ -int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) +int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data) { int ret; @@ -1655,11 +1655,11 @@ EXPORT_SYMBOL(phy_ethtool_get_eee); /** * phy_ethtool_set_eee - set EEE supported and status * @phydev: target phy_device struct - * @data: ethtool_eee data + * @data: ethtool_keee data * * Description: it is to program the Advertisement EEE register. */ -int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) +int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data) { int ret; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 3611ea64875e..52828d1c64f7 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1413,6 +1413,11 @@ int phy_sfp_probe(struct phy_device *phydev, } EXPORT_SYMBOL(phy_sfp_probe); +static bool phy_drv_supports_irq(struct phy_driver *phydrv) +{ + return phydrv->config_intr && phydrv->handle_interrupt; +} + /** * phy_attach_direct - attach a network device to a given PHY device pointer * @dev: network device to attach @@ -1527,6 +1532,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, if (phydev->dev_flags & PHY_F_NO_IRQ) phydev->irq = PHY_POLL; + if (!phy_drv_supports_irq(phydev->drv) && phy_interrupt_is_valid(phydev)) + phydev->irq = PHY_POLL; + /* Port is set to PORT_TP by default and the actual PHY driver will set * it to different value depending on the PHY configuration. If we have * the generic PHY driver we can't figure it out, thus set the old @@ -2992,11 +3000,6 @@ s32 phy_get_internal_delay(struct phy_device *phydev, struct device *dev, } EXPORT_SYMBOL(phy_get_internal_delay); -static bool phy_drv_supports_irq(struct phy_driver *phydrv) -{ - return phydrv->config_intr && phydrv->handle_interrupt; -} - static int phy_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness value) { @@ -3097,6 +3100,7 @@ static int of_phy_led(struct phy_device *phydev, struct device *dev = &phydev->mdio.dev; struct led_init_data init_data = {}; struct led_classdev *cdev; + unsigned long modes = 0; struct phy_led *phyled; u32 index; int err; @@ -3114,6 +3118,21 @@ static int of_phy_led(struct phy_device *phydev, if (index > U8_MAX) return -EINVAL; + if (of_property_read_bool(led, "active-low")) + set_bit(PHY_LED_ACTIVE_LOW, &modes); + if (of_property_read_bool(led, "inactive-high-impedance")) + set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); + + if (modes) { + /* Return error if asked to set polarity modes but not supported */ + if (!phydev->drv->led_polarity_set) + return -EINVAL; + + err = phydev->drv->led_polarity_set(phydev, index, modes); + if (err) + return err; + } + phyled->index = index; if (phydev->drv->led_brightness_set) cdev->brightness_set_blocking = phy_led_set_brightness; diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index ed0b4ccaa6a6..503fd7c40523 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2764,9 +2764,9 @@ EXPORT_SYMBOL_GPL(phylink_init_eee); /** * phylink_ethtool_get_eee() - read the energy efficient ethernet parameters * @pl: a pointer to a &struct phylink returned from phylink_create() - * @eee: a pointer to a &struct ethtool_eee for the read parameters + * @eee: a pointer to a &struct ethtool_keee for the read parameters */ -int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_eee *eee) +int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_keee *eee) { int ret = -EOPNOTSUPP; @@ -2782,9 +2782,9 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee); /** * phylink_ethtool_set_eee() - set the energy efficient ethernet parameters * @pl: a pointer to a &struct phylink returned from phylink_create() - * @eee: a pointer to a &struct ethtool_eee for the desired parameters + * @eee: a pointer to a &struct ethtool_keee for the desired parameters */ -int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_eee *eee) +int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_keee *eee) { int ret = -EOPNOTSUPP; diff --git a/drivers/net/phy/qcom/Kconfig b/drivers/net/phy/qcom/Kconfig new file mode 100644 index 000000000000..80db24deb689 --- /dev/null +++ b/drivers/net/phy/qcom/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only +config QCOM_NET_PHYLIB + tristate + +config AT803X_PHY + tristate "Qualcomm Atheros AR803X PHYs" + select QCOM_NET_PHYLIB + depends on REGULATOR + help + Currently supports the AR8030, AR8031, AR8033, AR8035 model + +config QCA83XX_PHY + tristate "Qualcomm Atheros QCA833x PHYs" + select QCOM_NET_PHYLIB + help + Currently supports the internal QCA8337(Internal qca8k PHY) model + +config QCA808X_PHY + tristate "Qualcomm QCA808x PHYs" + select QCOM_NET_PHYLIB + help + Currently supports the QCA8081 model diff --git a/drivers/net/phy/qcom/Makefile b/drivers/net/phy/qcom/Makefile new file mode 100644 index 000000000000..0362d7ed47be --- /dev/null +++ b/drivers/net/phy/qcom/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o +obj-$(CONFIG_AT803X_PHY) += at803x.o +obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o +obj-$(CONFIG_QCA808X_PHY) += qca808x.o diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c new file mode 100644 index 000000000000..36b70e88394e --- /dev/null +++ b/drivers/net/phy/qcom/at803x.c @@ -0,0 +1,1140 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * drivers/net/phy/at803x.c + * + * Driver for Qualcomm Atheros AR803x PHY + * + * Author: Matus Ujhelyi <ujhelyi.m@gmail.com> + */ + +#include <linux/phy.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool_netlink.h> +#include <linux/bitfield.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/consumer.h> +#include <linux/of.h> +#include <linux/phylink.h> +#include <linux/sfp.h> +#include <dt-bindings/net/qca-ar803x.h> + +#include "qcom.h" + +#define AT803X_LED_CONTROL 0x18 + +#define AT803X_PHY_MMD3_WOL_CTRL 0x8012 +#define AT803X_WOL_EN BIT(5) + +#define AT803X_REG_CHIP_CONFIG 0x1f +#define AT803X_BT_BX_REG_SEL 0x8000 + +#define AT803X_MODE_CFG_MASK 0x0F +#define AT803X_MODE_CFG_BASET_RGMII 0x00 +#define AT803X_MODE_CFG_BASET_SGMII 0x01 +#define AT803X_MODE_CFG_BX1000_RGMII_50OHM 0x02 +#define AT803X_MODE_CFG_BX1000_RGMII_75OHM 0x03 +#define AT803X_MODE_CFG_BX1000_CONV_50OHM 0x04 +#define AT803X_MODE_CFG_BX1000_CONV_75OHM 0x05 +#define AT803X_MODE_CFG_FX100_RGMII_50OHM 0x06 +#define AT803X_MODE_CFG_FX100_CONV_50OHM 0x07 +#define AT803X_MODE_CFG_RGMII_AUTO_MDET 0x0B +#define AT803X_MODE_CFG_FX100_RGMII_75OHM 0x0E +#define AT803X_MODE_CFG_FX100_CONV_75OHM 0x0F + +#define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/ +#define AT803X_PSSR_MR_AN_COMPLETE 0x0200 + +#define AT803X_DEBUG_REG_1F 0x1F +#define AT803X_DEBUG_PLL_ON BIT(2) +#define AT803X_DEBUG_RGMII_1V8 BIT(3) + +/* AT803x supports either the XTAL input pad, an internal PLL or the + * DSP as clock reference for the clock output pad. The XTAL reference + * is only used for 25 MHz output, all other frequencies need the PLL. + * The DSP as a clock reference is used in synchronous ethernet + * applications. + * + * By default the PLL is only enabled if there is a link. Otherwise + * the PHY will go into low power state and disabled the PLL. You can + * set the PLL_ON bit (see debug register 0x1f) to keep the PLL always + * enabled. + */ +#define AT803X_MMD7_CLK25M 0x8016 +#define AT803X_CLK_OUT_MASK GENMASK(4, 2) +#define AT803X_CLK_OUT_25MHZ_XTAL 0 +#define AT803X_CLK_OUT_25MHZ_DSP 1 +#define AT803X_CLK_OUT_50MHZ_PLL 2 +#define AT803X_CLK_OUT_50MHZ_DSP 3 +#define AT803X_CLK_OUT_62_5MHZ_PLL 4 +#define AT803X_CLK_OUT_62_5MHZ_DSP 5 +#define AT803X_CLK_OUT_125MHZ_PLL 6 +#define AT803X_CLK_OUT_125MHZ_DSP 7 + +/* The AR8035 has another mask which is compatible with the AR8031/AR8033 mask + * but doesn't support choosing between XTAL/PLL and DSP. + */ +#define AT8035_CLK_OUT_MASK GENMASK(4, 3) + +#define AT803X_CLK_OUT_STRENGTH_MASK GENMASK(8, 7) +#define AT803X_CLK_OUT_STRENGTH_FULL 0 +#define AT803X_CLK_OUT_STRENGTH_HALF 1 +#define AT803X_CLK_OUT_STRENGTH_QUARTER 2 + +#define AT803X_MMD3_SMARTEEE_CTL1 0x805b +#define AT803X_MMD3_SMARTEEE_CTL2 0x805c +#define AT803X_MMD3_SMARTEEE_CTL3 0x805d +#define AT803X_MMD3_SMARTEEE_CTL3_LPI_EN BIT(8) + +#define ATH9331_PHY_ID 0x004dd041 +#define ATH8030_PHY_ID 0x004dd076 +#define ATH8031_PHY_ID 0x004dd074 +#define ATH8032_PHY_ID 0x004dd023 +#define ATH8035_PHY_ID 0x004dd072 +#define AT8030_PHY_ID_MASK 0xffffffef + +#define QCA9561_PHY_ID 0x004dd042 + +#define AT803X_PAGE_FIBER 0 +#define AT803X_PAGE_COPPER 1 + +/* don't turn off internal PLL */ +#define AT803X_KEEP_PLL_ENABLED BIT(0) +#define AT803X_DISABLE_SMARTEEE BIT(1) + +/* disable hibernation mode */ +#define AT803X_DISABLE_HIBERNATION_MODE BIT(2) + +MODULE_DESCRIPTION("Qualcomm Atheros AR803x PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_LICENSE("GPL"); + +struct at803x_priv { + int flags; + u16 clk_25m_reg; + u16 clk_25m_mask; + u8 smarteee_lpi_tw_1g; + u8 smarteee_lpi_tw_100m; + bool is_fiber; + bool is_1000basex; + struct regulator_dev *vddio_rdev; + struct regulator_dev *vddh_rdev; +}; + +struct at803x_context { + u16 bmcr; + u16 advertise; + u16 control1000; + u16 int_enable; + u16 smart_speed; + u16 led_control; +}; + +static int at803x_write_page(struct phy_device *phydev, int page) +{ + int mask; + int set; + + if (page == AT803X_PAGE_COPPER) { + set = AT803X_BT_BX_REG_SEL; + mask = 0; + } else { + set = 0; + mask = AT803X_BT_BX_REG_SEL; + } + + return __phy_modify(phydev, AT803X_REG_CHIP_CONFIG, mask, set); +} + +static int at803x_read_page(struct phy_device *phydev) +{ + int ccr = __phy_read(phydev, AT803X_REG_CHIP_CONFIG); + + if (ccr < 0) + return ccr; + + if (ccr & AT803X_BT_BX_REG_SEL) + return AT803X_PAGE_COPPER; + + return AT803X_PAGE_FIBER; +} + +static int at803x_enable_rx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0, + AT803X_DEBUG_RX_CLK_DLY_EN); +} + +static int at803x_enable_tx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0, + AT803X_DEBUG_TX_CLK_DLY_EN); +} + +static int at803x_disable_rx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + AT803X_DEBUG_RX_CLK_DLY_EN, 0); +} + +static int at803x_disable_tx_delay(struct phy_device *phydev) +{ + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, + AT803X_DEBUG_TX_CLK_DLY_EN, 0); +} + +/* save relevant PHY registers to private copy */ +static void at803x_context_save(struct phy_device *phydev, + struct at803x_context *context) +{ + context->bmcr = phy_read(phydev, MII_BMCR); + context->advertise = phy_read(phydev, MII_ADVERTISE); + context->control1000 = phy_read(phydev, MII_CTRL1000); + context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE); + context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED); + context->led_control = phy_read(phydev, AT803X_LED_CONTROL); +} + +/* restore relevant PHY registers from private copy */ +static void at803x_context_restore(struct phy_device *phydev, + const struct at803x_context *context) +{ + phy_write(phydev, MII_BMCR, context->bmcr); + phy_write(phydev, MII_ADVERTISE, context->advertise); + phy_write(phydev, MII_CTRL1000, context->control1000); + phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable); + phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed); + phy_write(phydev, AT803X_LED_CONTROL, context->led_control); +} + +static int at803x_suspend(struct phy_device *phydev) +{ + int value; + int wol_enabled; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + wol_enabled = value & AT803X_INTR_ENABLE_WOL; + + if (wol_enabled) + value = BMCR_ISOLATE; + else + value = BMCR_PDOWN; + + phy_modify(phydev, MII_BMCR, 0, value); + + return 0; +} + +static int at803x_resume(struct phy_device *phydev) +{ + return phy_modify(phydev, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE, 0); +} + +static int at803x_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct at803x_priv *priv = phydev->priv; + u32 freq, strength, tw; + unsigned int sel; + int ret; + + if (!IS_ENABLED(CONFIG_OF_MDIO)) + return 0; + + if (of_property_read_bool(node, "qca,disable-smarteee")) + priv->flags |= AT803X_DISABLE_SMARTEEE; + + if (of_property_read_bool(node, "qca,disable-hibernation-mode")) + priv->flags |= AT803X_DISABLE_HIBERNATION_MODE; + + if (!of_property_read_u32(node, "qca,smarteee-tw-us-1g", &tw)) { + if (!tw || tw > 255) { + phydev_err(phydev, "invalid qca,smarteee-tw-us-1g\n"); + return -EINVAL; + } + priv->smarteee_lpi_tw_1g = tw; + } + + if (!of_property_read_u32(node, "qca,smarteee-tw-us-100m", &tw)) { + if (!tw || tw > 255) { + phydev_err(phydev, "invalid qca,smarteee-tw-us-100m\n"); + return -EINVAL; + } + priv->smarteee_lpi_tw_100m = tw; + } + + ret = of_property_read_u32(node, "qca,clk-out-frequency", &freq); + if (!ret) { + switch (freq) { + case 25000000: + sel = AT803X_CLK_OUT_25MHZ_XTAL; + break; + case 50000000: + sel = AT803X_CLK_OUT_50MHZ_PLL; + break; + case 62500000: + sel = AT803X_CLK_OUT_62_5MHZ_PLL; + break; + case 125000000: + sel = AT803X_CLK_OUT_125MHZ_PLL; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-frequency\n"); + return -EINVAL; + } + + priv->clk_25m_reg |= FIELD_PREP(AT803X_CLK_OUT_MASK, sel); + priv->clk_25m_mask |= AT803X_CLK_OUT_MASK; + } + + ret = of_property_read_u32(node, "qca,clk-out-strength", &strength); + if (!ret) { + priv->clk_25m_mask |= AT803X_CLK_OUT_STRENGTH_MASK; + switch (strength) { + case AR803X_STRENGTH_FULL: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_FULL; + break; + case AR803X_STRENGTH_HALF: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_HALF; + break; + case AR803X_STRENGTH_QUARTER: + priv->clk_25m_reg |= AT803X_CLK_OUT_STRENGTH_QUARTER; + break; + default: + phydev_err(phydev, "invalid qca,clk-out-strength\n"); + return -EINVAL; + } + } + + return 0; +} + +static int at803x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct at803x_priv *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + ret = at803x_parse_dt(phydev); + if (ret) + return ret; + + return 0; +} + +static int at803x_get_features(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int err; + + err = genphy_read_abilities(phydev); + if (err) + return err; + + if (phydev->drv->phy_id != ATH8031_PHY_ID) + return 0; + + /* AR8031/AR8033 have different status registers + * for copper and fiber operation. However, the + * extended status register is the same for both + * operation modes. + * + * As a result of that, ESTATUS_1000_XFULL is set + * to 1 even when operating in copper TP mode. + * + * Remove this mode from the supported link modes + * when not operating in 1000BaseX mode. + */ + if (!priv->is_1000basex) + linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + phydev->supported); + + return 0; +} + +static int at803x_smarteee_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + u16 mask = 0, val = 0; + int ret; + + if (priv->flags & AT803X_DISABLE_SMARTEEE) + return phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_MMD3_SMARTEEE_CTL3, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, 0); + + if (priv->smarteee_lpi_tw_1g) { + mask |= 0xff00; + val |= priv->smarteee_lpi_tw_1g << 8; + } + if (priv->smarteee_lpi_tw_100m) { + mask |= 0x00ff; + val |= priv->smarteee_lpi_tw_100m; + } + if (!mask) + return 0; + + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL1, + mask, val); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_PCS, AT803X_MMD3_SMARTEEE_CTL3, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN, + AT803X_MMD3_SMARTEEE_CTL3_LPI_EN); +} + +static int at803x_clk_out_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + if (!priv->clk_25m_mask) + return 0; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, AT803X_MMD7_CLK25M, + priv->clk_25m_mask, priv->clk_25m_reg); +} + +static int at8031_pll_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is PLL OFF. After a soft reset, the + * values are retained. + */ + if (priv->flags & AT803X_KEEP_PLL_ENABLED) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_PLL_ON); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_PLL_ON, 0); +} + +static int at803x_hibernation_mode_config(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* The default after hardware reset is hibernation mode enabled. After + * software reset, the value is retained. + */ + if (!(priv->flags & AT803X_DISABLE_HIBERNATION_MODE)) + return 0; + + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_PS_HIB_EN, 0); +} + +static int at803x_config_init(struct phy_device *phydev) +{ + int ret; + + /* The RX and TX delay default is: + * after HW reset: RX delay enabled and TX delay disabled + * after SW reset: RX delay enabled, while TX delay retains the + * value before reset. + */ + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + ret = at803x_enable_rx_delay(phydev); + else + ret = at803x_disable_rx_delay(phydev); + if (ret < 0) + return ret; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + ret = at803x_enable_tx_delay(phydev); + else + ret = at803x_disable_tx_delay(phydev); + if (ret < 0) + return ret; + + ret = at803x_smarteee_config(phydev); + if (ret < 0) + return ret; + + ret = at803x_clk_out_config(phydev); + if (ret < 0) + return ret; + + ret = at803x_hibernation_mode_config(phydev); + if (ret < 0) + return ret; + + /* Ar803x extended next page bit is enabled by default. Cisco + * multigig switches read this bit and attempt to negotiate 10Gbps + * rates even if the next page bit is disabled. This is incorrect + * behaviour but we still need to accommodate it. XNP is only needed + * for 10Gbps support, so disable XNP. + */ + return phy_modify(phydev, MII_ADVERTISE, MDIO_AN_CTRL1_XNP, 0); +} + +static void at803x_link_change_notify(struct phy_device *phydev) +{ + /* + * Conduct a hardware reset for AT8030 every time a link loss is + * signalled. This is necessary to circumvent a hardware bug that + * occurs when the cable is unplugged while TX packets are pending + * in the FIFO. In such cases, the FIFO enters an error mode it + * cannot recover from by software. + */ + if (phydev->state == PHY_NOLINK && phydev->mdio.reset_gpio) { + struct at803x_context context; + + at803x_context_save(phydev, &context); + + phy_device_reset(phydev, 1); + usleep_range(1000, 2000); + phy_device_reset(phydev, 0); + usleep_range(1000, 2000); + + at803x_context_restore(phydev, &context); + + phydev_dbg(phydev, "%s(): phy was reset\n", __func__); + } +} + +static int at803x_read_status(struct phy_device *phydev) +{ + struct at803x_ss_mask ss_mask = { 0 }; + int err, old_link = phydev->link; + + /* Update the link, but return if there was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + /* why bother the PHY if nothing can have changed */ + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + err = genphy_read_lpa(phydev); + if (err < 0) + return err; + + ss_mask.speed_mask = AT803X_SS_SPEED_MASK; + ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK); + err = at803x_read_specific_status(phydev, ss_mask); + if (err < 0) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) + phy_resolve_aneg_pause(phydev); + + return 0; +} + +static int at803x_config_aneg(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int ret; + + ret = at803x_prepare_config_aneg(phydev); + if (ret) + return ret; + + if (priv->is_1000basex) + return genphy_c37_config_aneg(phydev); + + return genphy_config_aneg(phydev); +} + +static int at803x_cable_test_result_trans(u16 status) +{ + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { + case AT803X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case AT803X_CDT_STATUS_STAT_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case AT803X_CDT_STATUS_STAT_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case AT803X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static bool at803x_cdt_test_failed(u16 status) +{ + return FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status) == + AT803X_CDT_STATUS_STAT_FAIL; +} + +static bool at803x_cdt_fault_length_valid(u16 status) +{ + switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) { + case AT803X_CDT_STATUS_STAT_OPEN: + case AT803X_CDT_STATUS_STAT_SHORT: + return true; + } + return false; +} + +static int at803x_cable_test_one_pair(struct phy_device *phydev, int pair) +{ + static const int ethtool_pair[] = { + ETHTOOL_A_CABLE_PAIR_A, + ETHTOOL_A_CABLE_PAIR_B, + ETHTOOL_A_CABLE_PAIR_C, + ETHTOOL_A_CABLE_PAIR_D, + }; + int ret, val; + + val = FIELD_PREP(AT803X_CDT_MDI_PAIR_MASK, pair) | + AT803X_CDT_ENABLE_TEST; + ret = at803x_cdt_start(phydev, val); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev, AT803X_CDT_ENABLE_TEST); + if (ret) + return ret; + + val = phy_read(phydev, AT803X_CDT_STATUS); + if (val < 0) + return val; + + if (at803x_cdt_test_failed(val)) + return 0; + + ethnl_cable_test_result(phydev, ethtool_pair[pair], + at803x_cable_test_result_trans(val)); + + if (at803x_cdt_fault_length_valid(val)) { + val = FIELD_GET(AT803X_CDT_STATUS_DELTA_TIME_MASK, val); + ethnl_cable_test_fault_length(phydev, ethtool_pair[pair], + at803x_cdt_fault_length(val)); + } + + return 1; +} + +static int at803x_cable_test_get_status(struct phy_device *phydev, + bool *finished, unsigned long pair_mask) +{ + int retries = 20; + int pair, ret; + + *finished = false; + + /* According to the datasheet the CDT can be performed when + * there is no link partner or when the link partner is + * auto-negotiating. Starting the test will restart the AN + * automatically. It seems that doing this repeatedly we will + * get a slot where our link partner won't disturb our + * measurement. + */ + while (pair_mask && retries--) { + for_each_set_bit(pair, &pair_mask, 4) { + ret = at803x_cable_test_one_pair(phydev, pair); + if (ret < 0) + return ret; + if (ret) + clear_bit(pair, &pair_mask); + } + if (pair_mask) + msleep(250); + } + + *finished = true; + + return 0; +} + +static void at803x_cable_test_autoneg(struct phy_device *phydev) +{ + /* Enable auto-negotiation, but advertise no capabilities, no link + * will be established. A restart of the auto-negotiation is not + * required, because the cable test will automatically break the link. + */ + phy_write(phydev, MII_BMCR, BMCR_ANENABLE); + phy_write(phydev, MII_ADVERTISE, ADVERTISE_CSMA); +} + +static int at803x_cable_test_start(struct phy_device *phydev) +{ + at803x_cable_test_autoneg(phydev); + /* we do all the (time consuming) work later */ + return 0; +} + +static int at8031_rgmii_reg_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + + if (selector) + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + 0, AT803X_DEBUG_RGMII_1V8); + else + return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_1F, + AT803X_DEBUG_RGMII_1V8, 0); +} + +static int at8031_rgmii_reg_get_voltage_sel(struct regulator_dev *rdev) +{ + struct phy_device *phydev = rdev_get_drvdata(rdev); + int val; + + val = at803x_debug_reg_read(phydev, AT803X_DEBUG_REG_1F); + if (val < 0) + return val; + + return (val & AT803X_DEBUG_RGMII_1V8) ? 1 : 0; +} + +static const struct regulator_ops vddio_regulator_ops = { + .list_voltage = regulator_list_voltage_table, + .set_voltage_sel = at8031_rgmii_reg_set_voltage_sel, + .get_voltage_sel = at8031_rgmii_reg_get_voltage_sel, +}; + +static const unsigned int vddio_voltage_table[] = { + 1500000, + 1800000, +}; + +static const struct regulator_desc vddio_desc = { + .name = "vddio", + .of_match = of_match_ptr("vddio-regulator"), + .n_voltages = ARRAY_SIZE(vddio_voltage_table), + .volt_table = vddio_voltage_table, + .ops = &vddio_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static const struct regulator_ops vddh_regulator_ops = { +}; + +static const struct regulator_desc vddh_desc = { + .name = "vddh", + .of_match = of_match_ptr("vddh-regulator"), + .n_voltages = 1, + .fixed_uV = 2500000, + .ops = &vddh_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int at8031_register_regulators(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + struct device *dev = &phydev->mdio.dev; + struct regulator_config config = { }; + + config.dev = dev; + config.driver_data = phydev; + + priv->vddio_rdev = devm_regulator_register(dev, &vddio_desc, &config); + if (IS_ERR(priv->vddio_rdev)) { + phydev_err(phydev, "failed to register VDDIO regulator\n"); + return PTR_ERR(priv->vddio_rdev); + } + + priv->vddh_rdev = devm_regulator_register(dev, &vddh_desc, &config); + if (IS_ERR(priv->vddh_rdev)) { + phydev_err(phydev, "failed to register VDDH regulator\n"); + return PTR_ERR(priv->vddh_rdev); + } + + return 0; +} + +static int at8031_sfp_insert(void *upstream, const struct sfp_eeprom_id *id) +{ + struct phy_device *phydev = upstream; + __ETHTOOL_DECLARE_LINK_MODE_MASK(phy_support); + __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support); + DECLARE_PHY_INTERFACE_MASK(interfaces); + phy_interface_t iface; + + linkmode_zero(phy_support); + phylink_set(phy_support, 1000baseX_Full); + phylink_set(phy_support, 1000baseT_Full); + phylink_set(phy_support, Autoneg); + phylink_set(phy_support, Pause); + phylink_set(phy_support, Asym_Pause); + + linkmode_zero(sfp_support); + sfp_parse_support(phydev->sfp_bus, id, sfp_support, interfaces); + /* Some modules support 10G modes as well as others we support. + * Mask out non-supported modes so the correct interface is picked. + */ + linkmode_and(sfp_support, phy_support, sfp_support); + + if (linkmode_empty(sfp_support)) { + dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n"); + return -EINVAL; + } + + iface = sfp_select_interface(phydev->sfp_bus, sfp_support); + + /* Only 1000Base-X is supported by AR8031/8033 as the downstream SerDes + * interface for use with SFP modules. + * However, some copper modules detected as having a preferred SGMII + * interface do default to and function in 1000Base-X mode, so just + * print a warning and allow such modules, as they may have some chance + * of working. + */ + if (iface == PHY_INTERFACE_MODE_SGMII) + dev_warn(&phydev->mdio.dev, "module may not function if 1000Base-X not supported\n"); + else if (iface != PHY_INTERFACE_MODE_1000BASEX) + return -EINVAL; + + return 0; +} + +static const struct sfp_upstream_ops at8031_sfp_ops = { + .attach = phy_sfp_attach, + .detach = phy_sfp_detach, + .module_insert = at8031_sfp_insert, +}; + +static int at8031_parse_dt(struct phy_device *phydev) +{ + struct device_node *node = phydev->mdio.dev.of_node; + struct at803x_priv *priv = phydev->priv; + int ret; + + if (of_property_read_bool(node, "qca,keep-pll-enabled")) + priv->flags |= AT803X_KEEP_PLL_ENABLED; + + ret = at8031_register_regulators(phydev); + if (ret < 0) + return ret; + + ret = devm_regulator_get_enable_optional(&phydev->mdio.dev, + "vddio"); + if (ret) { + phydev_err(phydev, "failed to get VDDIO regulator\n"); + return ret; + } + + /* Only AR8031/8033 support 1000Base-X for SFP modules */ + return phy_sfp_probe(phydev, &at8031_sfp_ops); +} + +static int at8031_probe(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int mode_cfg; + int ccr; + int ret; + + ret = at803x_probe(phydev); + if (ret) + return ret; + + /* Only supported on AR8031/AR8033, the AR8030/AR8035 use strapping + * options. + */ + ret = at8031_parse_dt(phydev); + if (ret) + return ret; + + ccr = phy_read(phydev, AT803X_REG_CHIP_CONFIG); + if (ccr < 0) + return ccr; + mode_cfg = ccr & AT803X_MODE_CFG_MASK; + + switch (mode_cfg) { + case AT803X_MODE_CFG_BX1000_RGMII_50OHM: + case AT803X_MODE_CFG_BX1000_RGMII_75OHM: + priv->is_1000basex = true; + fallthrough; + case AT803X_MODE_CFG_FX100_RGMII_50OHM: + case AT803X_MODE_CFG_FX100_RGMII_75OHM: + priv->is_fiber = true; + break; + } + + /* Disable WoL in 1588 register which is enabled + * by default + */ + return phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); +} + +static int at8031_config_init(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int ret; + + /* Some bootloaders leave the fiber page selected. + * Switch to the appropriate page (fiber or copper), as otherwise we + * read the PHY capabilities from the wrong page. + */ + phy_lock_mdio_bus(phydev); + ret = at803x_write_page(phydev, + priv->is_fiber ? AT803X_PAGE_FIBER : + AT803X_PAGE_COPPER); + phy_unlock_mdio_bus(phydev); + if (ret) + return ret; + + ret = at8031_pll_config(phydev); + if (ret < 0) + return ret; + + return at803x_config_init(phydev); +} + +static int at8031_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret; + + /* First setup MAC address and enable WOL interrupt */ + ret = at803x_set_wol(phydev, wol); + if (ret) + return ret; + + if (wol->wolopts & WAKE_MAGIC) + /* Enable WOL function for 1588 */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + 0, AT803X_WOL_EN); + else + /* Disable WoL function for 1588 */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, + AT803X_PHY_MMD3_WOL_CTRL, + AT803X_WOL_EN, 0); + + return ret; +} + +static int at8031_config_intr(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + int err, value = 0; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED && + priv->is_fiber) { + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + if (err) + return err; + + value |= AT803X_INTR_ENABLE_LINK_FAIL_BX; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS_BX; + + err = phy_set_bits(phydev, AT803X_INTR_ENABLE, value); + if (err) + return err; + } + + return at803x_config_intr(phydev); +} + +/* AR8031 and AR8033 share the same read status logic */ +static int at8031_read_status(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + if (priv->is_1000basex) + return genphy_c37_read_status(phydev); + + return at803x_read_status(phydev); +} + +/* AR8031 and AR8035 share the same cable test get status reg */ +static int at8031_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + return at803x_cable_test_get_status(phydev, finished, 0xf); +} + +/* AR8031 and AR8035 share the same cable test start logic */ +static int at8031_cable_test_start(struct phy_device *phydev) +{ + at803x_cable_test_autoneg(phydev); + phy_write(phydev, MII_CTRL1000, 0); + /* we do all the (time consuming) work later */ + return 0; +} + +/* AR8032, AR9331 and QCA9561 share the same cable test get status reg */ +static int at8032_cable_test_get_status(struct phy_device *phydev, + bool *finished) +{ + return at803x_cable_test_get_status(phydev, finished, 0x3); +} + +static int at8035_parse_dt(struct phy_device *phydev) +{ + struct at803x_priv *priv = phydev->priv; + + /* Mask is set by the generic at803x_parse_dt + * if property is set. Assume property is set + * with the mask not zero. + */ + if (priv->clk_25m_mask) { + /* Fixup for the AR8030/AR8035. This chip has another mask and + * doesn't support the DSP reference. Eg. the lowest bit of the + * mask. The upper two bits select the same frequencies. Mask + * the lowest bit here. + * + * Warning: + * There was no datasheet for the AR8030 available so this is + * just a guess. But the AR8035 is listed as pin compatible + * to the AR8030 so there might be a good chance it works on + * the AR8030 too. + */ + priv->clk_25m_reg &= AT8035_CLK_OUT_MASK; + priv->clk_25m_mask &= AT8035_CLK_OUT_MASK; + } + + return 0; +} + +/* AR8030 and AR8035 shared the same special mask for clk_25m */ +static int at8035_probe(struct phy_device *phydev) +{ + int ret; + + ret = at803x_probe(phydev); + if (ret) + return ret; + + return at8035_parse_dt(phydev); +} + +static struct phy_driver at803x_driver[] = { +{ + /* Qualcomm Atheros AR8035 */ + PHY_ID_MATCH_EXACT(ATH8035_PHY_ID), + .name = "Qualcomm Atheros AR8035", + .flags = PHY_POLL_CABLE_TEST, + .probe = at8035_probe, + .config_aneg = at803x_config_aneg, + .config_init = at803x_config_init, + .soft_reset = genphy_soft_reset, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_GBIT_FEATURES */ + .read_status = at803x_read_status, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .cable_test_start = at8031_cable_test_start, + .cable_test_get_status = at8031_cable_test_get_status, +}, { + /* Qualcomm Atheros AR8030 */ + .phy_id = ATH8030_PHY_ID, + .name = "Qualcomm Atheros AR8030", + .phy_id_mask = AT8030_PHY_ID_MASK, + .probe = at8035_probe, + .config_init = at803x_config_init, + .link_change_notify = at803x_link_change_notify, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, +}, { + /* Qualcomm Atheros AR8031/AR8033 */ + PHY_ID_MATCH_EXACT(ATH8031_PHY_ID), + .name = "Qualcomm Atheros AR8031/AR8033", + .flags = PHY_POLL_CABLE_TEST, + .probe = at8031_probe, + .config_init = at8031_config_init, + .config_aneg = at803x_config_aneg, + .soft_reset = genphy_soft_reset, + .set_wol = at8031_set_wol, + .get_wol = at803x_get_wol, + .suspend = at803x_suspend, + .resume = at803x_resume, + .read_page = at803x_read_page, + .write_page = at803x_write_page, + .get_features = at803x_get_features, + .read_status = at8031_read_status, + .config_intr = at8031_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .cable_test_start = at8031_cable_test_start, + .cable_test_get_status = at8031_cable_test_get_status, +}, { + /* Qualcomm Atheros AR8032 */ + PHY_ID_MATCH_EXACT(ATH8032_PHY_ID), + .name = "Qualcomm Atheros AR8032", + .probe = at803x_probe, + .flags = PHY_POLL_CABLE_TEST, + .config_init = at803x_config_init, + .link_change_notify = at803x_link_change_notify, + .suspend = at803x_suspend, + .resume = at803x_resume, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at8032_cable_test_get_status, +}, { + /* ATHEROS AR9331 */ + PHY_ID_MATCH_EXACT(ATH9331_PHY_ID), + .name = "Qualcomm Atheros AR9331 built-in PHY", + .probe = at803x_probe, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at8032_cable_test_get_status, + .read_status = at803x_read_status, + .soft_reset = genphy_soft_reset, + .config_aneg = at803x_config_aneg, +}, { + /* Qualcomm Atheros QCA9561 */ + PHY_ID_MATCH_EXACT(QCA9561_PHY_ID), + .name = "Qualcomm Atheros QCA9561 built-in PHY", + .probe = at803x_probe, + .suspend = at803x_suspend, + .resume = at803x_resume, + .flags = PHY_POLL_CABLE_TEST, + /* PHY_BASIC_FEATURES */ + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .cable_test_start = at803x_cable_test_start, + .cable_test_get_status = at8032_cable_test_get_status, + .read_status = at803x_read_status, + .soft_reset = genphy_soft_reset, + .config_aneg = at803x_config_aneg, +}, }; + +module_phy_driver(at803x_driver); + +static struct mdio_device_id __maybe_unused atheros_tbl[] = { + { ATH8030_PHY_ID, AT8030_PHY_ID_MASK }, + { PHY_ID_MATCH_EXACT(ATH8031_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) }, + { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, atheros_tbl); diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c new file mode 100644 index 000000000000..0f549027d899 --- /dev/null +++ b/drivers/net/phy/qcom/qca808x.c @@ -0,0 +1,934 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/phy.h> +#include <linux/module.h> +#include <linux/ethtool_netlink.h> + +#include "qcom.h" + +/* ADC threshold */ +#define QCA808X_PHY_DEBUG_ADC_THRESHOLD 0x2c80 +#define QCA808X_ADC_THRESHOLD_MASK GENMASK(7, 0) +#define QCA808X_ADC_THRESHOLD_80MV 0 +#define QCA808X_ADC_THRESHOLD_100MV 0xf0 +#define QCA808X_ADC_THRESHOLD_200MV 0x0f +#define QCA808X_ADC_THRESHOLD_300MV 0xff + +/* CLD control */ +#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 +#define QCA808X_8023AZ_AFE_CTRL_MASK GENMASK(8, 4) +#define QCA808X_8023AZ_AFE_EN 0x90 + +/* AZ control */ +#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 +#define QCA808X_MMD3_AZ_TRAINING_VAL 0x1c32 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB 0x8014 +#define QCA808X_MSE_THRESHOLD_20DB_VALUE 0x529 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB 0x800E +#define QCA808X_MSE_THRESHOLD_17DB_VALUE 0x341 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB 0x801E +#define QCA808X_MSE_THRESHOLD_27DB_VALUE 0x419 + +#define QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB 0x8020 +#define QCA808X_MSE_THRESHOLD_28DB_VALUE 0x341 + +#define QCA808X_PHY_MMD7_TOP_OPTION1 0x901c +#define QCA808X_TOP_OPTION1_DATA 0x0 + +#define QCA808X_PHY_MMD3_DEBUG_1 0xa100 +#define QCA808X_MMD3_DEBUG_1_VALUE 0x9203 +#define QCA808X_PHY_MMD3_DEBUG_2 0xa101 +#define QCA808X_MMD3_DEBUG_2_VALUE 0x48ad +#define QCA808X_PHY_MMD3_DEBUG_3 0xa103 +#define QCA808X_MMD3_DEBUG_3_VALUE 0x1698 +#define QCA808X_PHY_MMD3_DEBUG_4 0xa105 +#define QCA808X_MMD3_DEBUG_4_VALUE 0x8001 +#define QCA808X_PHY_MMD3_DEBUG_5 0xa106 +#define QCA808X_MMD3_DEBUG_5_VALUE 0x1111 +#define QCA808X_PHY_MMD3_DEBUG_6 0xa011 +#define QCA808X_MMD3_DEBUG_6_VALUE 0x5f85 + +/* master/slave seed config */ +#define QCA808X_PHY_DEBUG_LOCAL_SEED 9 +#define QCA808X_MASTER_SLAVE_SEED_ENABLE BIT(1) +#define QCA808X_MASTER_SLAVE_SEED_CFG GENMASK(12, 2) +#define QCA808X_MASTER_SLAVE_SEED_RANGE 0x32 + +/* Hibernation yields lower power consumpiton in contrast with normal operation mode. + * when the copper cable is unplugged, the PHY enters into hibernation mode in about 10s. + */ +#define QCA808X_DBG_AN_TEST 0xb +#define QCA808X_HIBERNATION_EN BIT(15) + +#define QCA808X_CDT_ENABLE_TEST BIT(15) +#define QCA808X_CDT_INTER_CHECK_DIS BIT(13) +#define QCA808X_CDT_STATUS BIT(11) +#define QCA808X_CDT_LENGTH_UNIT BIT(10) + +#define QCA808X_MMD3_CDT_STATUS 0x8064 +#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065 +#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066 +#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067 +#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068 +#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8) +#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0) + +#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12) +#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8) +#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4) +#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0) + +#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0) +#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0) +#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1) +#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2) +#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3) + +#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2) +#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1) +#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2) +#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3) + +/* NORMAL are MDI with type set to 0 */ +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI1) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI2) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3 +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\ + QCA808X_CDT_STATUS_STAT_MDI3) +#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\ + QCA808X_CDT_STATUS_STAT_MDI3) + +/* Added for reference of existence but should be handled by wait_for_completion already */ +#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) + +#define QCA808X_MMD7_LED_GLOBAL 0x8073 +#define QCA808X_LED_BLINK_1 GENMASK(11, 6) +#define QCA808X_LED_BLINK_2 GENMASK(5, 0) +/* Values are the same for both BLINK_1 and BLINK_2 */ +#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) +#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) +#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) +#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) +#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) +#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) +#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) +#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) +#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) +#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) +#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) +#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) +#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) +#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) +#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) +#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) +#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) +#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) + +#define QCA808X_MMD7_LED2_CTRL 0x8074 +#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 +#define QCA808X_MMD7_LED1_CTRL 0x8076 +#define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077 +#define QCA808X_MMD7_LED0_CTRL 0x8078 +#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) + +/* LED hw control pattern is the same for every LED */ +#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) +#define QCA808X_LED_SPEED2500_ON BIT(15) +#define QCA808X_LED_SPEED2500_BLINK BIT(14) +/* Follow blink trigger even if duplex or speed condition doesn't match */ +#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) +#define QCA808X_LED_FULL_DUPLEX_ON BIT(12) +#define QCA808X_LED_HALF_DUPLEX_ON BIT(11) +#define QCA808X_LED_TX_BLINK BIT(10) +#define QCA808X_LED_RX_BLINK BIT(9) +#define QCA808X_LED_TX_ON_10MS BIT(8) +#define QCA808X_LED_RX_ON_10MS BIT(7) +#define QCA808X_LED_SPEED1000_ON BIT(6) +#define QCA808X_LED_SPEED100_ON BIT(5) +#define QCA808X_LED_SPEED10_ON BIT(4) +#define QCA808X_LED_COLLISION_BLINK BIT(3) +#define QCA808X_LED_SPEED1000_BLINK BIT(2) +#define QCA808X_LED_SPEED100_BLINK BIT(1) +#define QCA808X_LED_SPEED10_BLINK BIT(0) + +#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 +#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) + +/* LED force ctrl is the same for every LED + * No documentation exist for this, not even internal one + * with NDA as QCOM gives only info about configuring + * hw control pattern rules and doesn't indicate any way + * to force the LED to specific mode. + * These define comes from reverse and testing and maybe + * lack of some info or some info are not entirely correct. + * For the basic LED control and hw control these finding + * are enough to support LED control in all the required APIs. + * + * On doing some comparison with implementation with qca807x, + * it was found that it's 1:1 equal to it and confirms all the + * reverse done. It was also found further specification with the + * force mode and the blink modes. + */ +#define QCA808X_LED_FORCE_EN BIT(15) +#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) +#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) +#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) +#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) +#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) + +#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a +/* QSDK sets by default 0x46 to this reg that sets BIT 6 for + * LED to active high. It's not clear what BIT 3 and BIT 4 does. + */ +#define QCA808X_LED_ACTIVE_HIGH BIT(6) + +/* QCA808X 1G chip type */ +#define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d +#define QCA808X_PHY_CHIP_TYPE_1G BIT(0) + +#define QCA8081_PHY_SERDES_MMD1_FIFO_CTRL 0x9072 +#define QCA8081_PHY_FIFO_RSTN BIT(11) + +#define QCA8081_PHY_ID 0x004dd101 + +MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_LICENSE("GPL"); + +struct qca808x_priv { + int led_polarity_mode; +}; + +static int qca808x_phy_fast_retrain_config(struct phy_device *phydev) +{ + int ret; + + /* Enable fast retrain */ + ret = genphy_c45_fast_retrain(phydev, true); + if (ret) + return ret; + + phy_write_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_TOP_OPTION1, + QCA808X_TOP_OPTION1_DATA); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_20DB, + QCA808X_MSE_THRESHOLD_20DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_17DB, + QCA808X_MSE_THRESHOLD_17DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_27DB, + QCA808X_MSE_THRESHOLD_27DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PMAPMD, QCA808X_PHY_MMD1_MSE_THRESHOLD_28DB, + QCA808X_MSE_THRESHOLD_28DB_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_1, + QCA808X_MMD3_DEBUG_1_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_4, + QCA808X_MMD3_DEBUG_4_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_5, + QCA808X_MMD3_DEBUG_5_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_3, + QCA808X_MMD3_DEBUG_3_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_6, + QCA808X_MMD3_DEBUG_6_VALUE); + phy_write_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_DEBUG_2, + QCA808X_MMD3_DEBUG_2_VALUE); + + return 0; +} + +static int qca808x_phy_ms_seed_enable(struct phy_device *phydev, bool enable) +{ + u16 seed_value; + + if (!enable) + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_ENABLE, 0); + + seed_value = get_random_u32_below(QCA808X_MASTER_SLAVE_SEED_RANGE); + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_LOCAL_SEED, + QCA808X_MASTER_SLAVE_SEED_CFG | QCA808X_MASTER_SLAVE_SEED_ENABLE, + FIELD_PREP(QCA808X_MASTER_SLAVE_SEED_CFG, seed_value) | + QCA808X_MASTER_SLAVE_SEED_ENABLE); +} + +static bool qca808x_is_prefer_master(struct phy_device *phydev) +{ + return (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_FORCE) || + (phydev->master_slave_get == MASTER_SLAVE_CFG_MASTER_PREFERRED); +} + +static bool qca808x_has_fast_retrain_or_slave_seed(struct phy_device *phydev) +{ + return linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); +} + +static int qca808x_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca808x_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Init LED polarity mode to -1 */ + priv->led_polarity_mode = -1; + + phydev->priv = priv; + + return 0; +} + +static int qca808x_config_init(struct phy_device *phydev) +{ + int ret; + + /* Active adc&vga on 802.3az for the link 1000M and 100M */ + ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, QCA808X_PHY_MMD3_ADDR_CLD_CTRL7, + QCA808X_8023AZ_AFE_CTRL_MASK, QCA808X_8023AZ_AFE_EN); + if (ret) + return ret; + + /* Adjust the threshold on 802.3az for the link 1000M */ + ret = phy_write_mmd(phydev, MDIO_MMD_PCS, + QCA808X_PHY_MMD3_AZ_TRAINING_CTRL, + QCA808X_MMD3_AZ_TRAINING_VAL); + if (ret) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + /* Config the fast retrain for the link 2500M */ + ret = qca808x_phy_fast_retrain_config(phydev); + if (ret) + return ret; + + ret = genphy_read_master_slave(phydev); + if (ret < 0) + return ret; + + if (!qca808x_is_prefer_master(phydev)) { + /* Enable seed and configure lower ramdom seed to make phy + * linked as slave mode. + */ + ret = qca808x_phy_ms_seed_enable(phydev, true); + if (ret) + return ret; + } + } + + /* Configure adc threshold as 100mv for the link 10M */ + return at803x_debug_reg_mask(phydev, QCA808X_PHY_DEBUG_ADC_THRESHOLD, + QCA808X_ADC_THRESHOLD_MASK, + QCA808X_ADC_THRESHOLD_100MV); +} + +static int qca808x_read_status(struct phy_device *phydev) +{ + struct at803x_ss_mask ss_mask = { 0 }; + int ret; + + ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT); + if (ret < 0) + return ret; + + linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->lp_advertising, + ret & MDIO_AN_10GBT_STAT_LP2_5G); + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + /* qca8081 takes the different bits for speed value from at803x */ + ss_mask.speed_mask = QCA808X_SS_SPEED_MASK; + ss_mask.speed_shift = __bf_shf(QCA808X_SS_SPEED_MASK); + ret = at803x_read_specific_status(phydev, ss_mask); + if (ret < 0) + return ret; + + if (phydev->link) { + if (phydev->speed == SPEED_2500) + phydev->interface = PHY_INTERFACE_MODE_2500BASEX; + else + phydev->interface = PHY_INTERFACE_MODE_SGMII; + } else { + /* generate seed as a lower random value to make PHY linked as SLAVE easily, + * except for master/slave configuration fault detected or the master mode + * preferred. + * + * the reason for not putting this code into the function link_change_notify is + * the corner case where the link partner is also the qca8081 PHY and the seed + * value is configured as the same value, the link can't be up and no link change + * occurs. + */ + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) { + if (phydev->master_slave_state == MASTER_SLAVE_STATE_ERR || + qca808x_is_prefer_master(phydev)) { + qca808x_phy_ms_seed_enable(phydev, false); + } else { + qca808x_phy_ms_seed_enable(phydev, true); + } + } + } + + return 0; +} + +static int qca808x_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + + if (qca808x_has_fast_retrain_or_slave_seed(phydev)) + ret = qca808x_phy_ms_seed_enable(phydev, true); + + return ret; +} + +static bool qca808x_cdt_fault_length_valid(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return true; + default: + return false; + } +} + +static int qca808x_cable_test_result_trans(int cdt_code) +{ + switch (cdt_code) { + case QCA808X_CDT_STATUS_STAT_NORMAL: + return ETHTOOL_A_CABLE_RESULT_CODE_OK; + case QCA808X_CDT_STATUS_STAT_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT; + case QCA808X_CDT_STATUS_STAT_SAME_OPEN: + return ETHTOOL_A_CABLE_RESULT_CODE_OPEN; + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN: + case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT: + return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT; + case QCA808X_CDT_STATUS_STAT_FAIL: + default: + return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC; + } +} + +static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair, + int result) +{ + int val; + u32 cdt_length_reg = 0; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A; + break; + case ETHTOOL_A_CABLE_PAIR_B: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B; + break; + case ETHTOOL_A_CABLE_PAIR_C: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C; + break; + case ETHTOOL_A_CABLE_PAIR_D: + cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D; + break; + default: + return -EINVAL; + } + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg); + if (val < 0) + return val; + + if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT) + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val); + else + val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val); + + return at803x_cdt_fault_length(val); +} + +static int qca808x_cable_test_start(struct phy_device *phydev) +{ + int ret; + + /* perform CDT with the following configs: + * 1. disable hibernation. + * 2. force PHY working in MDI mode. + * 3. for PHY working in 1000BaseT. + * 4. configure the threshold. + */ + + ret = at803x_debug_reg_mask(phydev, QCA808X_DBG_AN_TEST, QCA808X_HIBERNATION_EN, 0); + if (ret < 0) + return ret; + + ret = at803x_config_mdix(phydev, ETH_TP_MDI); + if (ret < 0) + return ret; + + /* Force 1000base-T needs to configure PMA/PMD and MII_BMCR */ + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + ret = genphy_c45_pma_setup_forced(phydev); + if (ret < 0) + return ret; + + ret = genphy_setup_forced(phydev); + if (ret < 0) + return ret; + + /* configure the thresholds for open, short, pair ok test */ + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8074, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8076, 0xc040); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8077, 0xa060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x8078, 0xc050); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807a, 0xc060); + phy_write_mmd(phydev, MDIO_MMD_PCS, 0x807e, 0xb060); + + return 0; +} + +static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair, + u16 status) +{ + int length, result; + u16 pair_code; + + switch (pair) { + case ETHTOOL_A_CABLE_PAIR_A: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status); + break; + case ETHTOOL_A_CABLE_PAIR_B: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status); + break; + case ETHTOOL_A_CABLE_PAIR_C: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status); + break; + case ETHTOOL_A_CABLE_PAIR_D: + pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status); + break; + default: + return -EINVAL; + } + + result = qca808x_cable_test_result_trans(pair_code); + ethnl_cable_test_result(phydev, pair, result); + + if (qca808x_cdt_fault_length_valid(pair_code)) { + length = qca808x_cdt_fault_length(phydev, pair, result); + ethnl_cable_test_fault_length(phydev, pair, length); + } + + return 0; +} + +static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished) +{ + int ret, val; + + *finished = false; + + val = QCA808X_CDT_ENABLE_TEST | + QCA808X_CDT_LENGTH_UNIT; + ret = at803x_cdt_start(phydev, val); + if (ret) + return ret; + + ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST); + if (ret) + return ret; + + val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS); + if (val < 0) + return val; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val); + if (ret) + return ret; + + ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val); + if (ret) + return ret; + + *finished = true; + + return 0; +} + +static int qca808x_get_features(struct phy_device *phydev) +{ + int ret; + + ret = genphy_c45_pma_read_abilities(phydev); + if (ret) + return ret; + + /* The autoneg ability is not existed in bit3 of MMD7.1, + * but it is supported by qca808x PHY, so we add it here + * manually. + */ + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->supported); + + /* As for the qca8081 1G version chip, the 2500baseT ability is also + * existed in the bit0 of MMD1.21, we need to remove it manually if + * it is the qca8081 1G chip according to the bit0 of MMD7.0x901d. + */ + ret = phy_read_mmd(phydev, MDIO_MMD_AN, QCA808X_PHY_MMD7_CHIP_TYPE); + if (ret < 0) + return ret; + + if (QCA808X_PHY_CHIP_TYPE_1G & ret) + linkmode_clear_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported); + + return 0; +} + +static int qca808x_config_aneg(struct phy_device *phydev) +{ + int phy_ctrl = 0; + int ret; + + ret = at803x_prepare_config_aneg(phydev); + if (ret) + return ret; + + /* The reg MII_BMCR also needs to be configured for force mode, the + * genphy_config_aneg is also needed. + */ + if (phydev->autoneg == AUTONEG_DISABLE) + genphy_c45_pma_setup_forced(phydev); + + if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->advertising)) + phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G; + + ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL, + MDIO_AN_10GBT_CTRL_ADV2_5G, phy_ctrl); + if (ret < 0) + return ret; + + return __genphy_config_aneg(phydev, ret); +} + +static void qca808x_link_change_notify(struct phy_device *phydev) +{ + /* Assert interface sgmii fifo on link down, deassert it on link up, + * the interface device address is always phy address added by 1. + */ + mdiobus_c45_modify_changed(phydev->mdio.bus, phydev->mdio.addr + 1, + MDIO_MMD_PMAPMD, QCA8081_PHY_SERDES_MMD1_FIFO_CTRL, + QCA8081_PHY_FIFO_RSTN, + phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); +} + +static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, + u16 *offload_trigger) +{ + /* Parsing specific to netdev trigger */ + if (test_bit(TRIGGER_NETDEV_TX, &rules)) + *offload_trigger |= QCA808X_LED_TX_BLINK; + if (test_bit(TRIGGER_NETDEV_RX, &rules)) + *offload_trigger |= QCA808X_LED_RX_BLINK; + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) + *offload_trigger |= QCA808X_LED_SPEED10_ON; + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) + *offload_trigger |= QCA808X_LED_SPEED100_ON; + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) + *offload_trigger |= QCA808X_LED_SPEED1000_ON; + if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules)) + *offload_trigger |= QCA808X_LED_SPEED2500_ON; + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; + + if (rules && !*offload_trigger) + return -EOPNOTSUPP; + + /* Enable BLINK_CHECK_BYPASS by default to make the LED + * blink even with duplex or speed mode not enabled. + */ + *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS; + + return 0; +} + +static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 offload_trigger = 0; + + if (index > 2) + return -EINVAL; + + return qca808x_led_parse_netdev(phydev, rules, &offload_trigger); +} + +static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, + unsigned long rules) +{ + u16 reg, offload_trigger = 0; + int ret; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger); + if (ret) + return ret; + + ret = qca808x_led_hw_control_enable(phydev, index); + if (ret) + return ret; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK, + offload_trigger); +} + +static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) +{ + u16 reg; + int val; + + if (index > 2) + return false; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + + return !(val & QCA808X_LED_FORCE_EN); +} + +static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, + unsigned long *rules) +{ + u16 reg; + int val; + + if (index > 2) + return -EINVAL; + + /* Check if we have hw control enabled */ + if (qca808x_led_hw_control_status(phydev, index)) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); + if (val & QCA808X_LED_TX_BLINK) + set_bit(TRIGGER_NETDEV_TX, rules); + if (val & QCA808X_LED_RX_BLINK) + set_bit(TRIGGER_NETDEV_RX, rules); + if (val & QCA808X_LED_SPEED10_ON) + set_bit(TRIGGER_NETDEV_LINK_10, rules); + if (val & QCA808X_LED_SPEED100_ON) + set_bit(TRIGGER_NETDEV_LINK_100, rules); + if (val & QCA808X_LED_SPEED1000_ON) + set_bit(TRIGGER_NETDEV_LINK_1000, rules); + if (val & QCA808X_LED_SPEED2500_ON) + set_bit(TRIGGER_NETDEV_LINK_2500, rules); + if (val & QCA808X_LED_HALF_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); + if (val & QCA808X_LED_FULL_DUPLEX_ON) + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); + + return 0; +} + +static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index) +{ + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_CTRL(index); + + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_PATTERN_MASK); +} + +static int qca808x_led_brightness_set(struct phy_device *phydev, + u8 index, enum led_brightness value) +{ + u16 reg; + int ret; + + if (index > 2) + return -EINVAL; + + if (!value) { + ret = qca808x_led_hw_control_reset(phydev, index); + if (ret) + return ret; + } + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : + QCA808X_LED_FORCE_OFF); +} + +static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *delay_on, + unsigned long *delay_off) +{ + int ret; + u16 reg; + + if (index > 2) + return -EINVAL; + + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); + + /* Set blink to 50% off, 50% on at 4Hz by default */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); + if (ret) + return ret; + + /* We use BLINK_1 for normal blinking */ + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); + if (ret) + return ret; + + /* We set blink to 4Hz, aka 250ms */ + *delay_on = 250 / 2; + *delay_off = 250 / 2; + + return 0; +} + +static int qca808x_led_polarity_set(struct phy_device *phydev, int index, + unsigned long modes) +{ + struct qca808x_priv *priv = phydev->priv; + bool active_low = false; + u32 mode; + + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { + switch (mode) { + case PHY_LED_ACTIVE_LOW: + active_low = true; + break; + default: + return -EINVAL; + } + } + + /* PHY polarity is global and can't be set per LED. + * To detect this, check if last requested polarity mode + * match the new one. + */ + if (priv->led_polarity_mode >= 0 && + priv->led_polarity_mode != active_low) { + phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); + return -EINVAL; + } + + /* Save the last PHY polarity mode */ + priv->led_polarity_mode = active_low; + + return phy_modify_mmd(phydev, MDIO_MMD_AN, + QCA808X_MMD7_LED_POLARITY_CTRL, + QCA808X_LED_ACTIVE_HIGH, + active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); +} + +static struct phy_driver qca808x_driver[] = { +{ + /* Qualcomm QCA8081 */ + PHY_ID_MATCH_EXACT(QCA8081_PHY_ID), + .name = "Qualcomm QCA8081", + .flags = PHY_POLL_CABLE_TEST, + .probe = qca808x_probe, + .config_intr = at803x_config_intr, + .handle_interrupt = at803x_handle_interrupt, + .get_tunable = at803x_get_tunable, + .set_tunable = at803x_set_tunable, + .set_wol = at803x_set_wol, + .get_wol = at803x_get_wol, + .get_features = qca808x_get_features, + .config_aneg = qca808x_config_aneg, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_status = qca808x_read_status, + .config_init = qca808x_config_init, + .soft_reset = qca808x_soft_reset, + .cable_test_start = qca808x_cable_test_start, + .cable_test_get_status = qca808x_cable_test_get_status, + .link_change_notify = qca808x_link_change_notify, + .led_brightness_set = qca808x_led_brightness_set, + .led_blink_set = qca808x_led_blink_set, + .led_hw_is_supported = qca808x_led_hw_is_supported, + .led_hw_control_set = qca808x_led_hw_control_set, + .led_hw_control_get = qca808x_led_hw_control_get, + .led_polarity_set = qca808x_led_polarity_set, +}, }; + +module_phy_driver(qca808x_driver); + +static struct mdio_device_id __maybe_unused qca808x_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qca808x_tbl); diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c new file mode 100644 index 000000000000..5d083ef0250e --- /dev/null +++ b/drivers/net/phy/qcom/qca83xx.c @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/phy.h> +#include <linux/module.h> + +#include "qcom.h" + +#define AT803X_DEBUG_REG_3C 0x3C + +#define AT803X_DEBUG_REG_GREEN 0x3D +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6) + +#define MDIO_AZ_DEBUG 0x800D + +#define QCA8327_A_PHY_ID 0x004dd033 +#define QCA8327_B_PHY_ID 0x004dd034 +#define QCA8337_PHY_ID 0x004dd036 +#define QCA8K_PHY_ID_MASK 0xffffffff + +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0) + +static struct at803x_hw_stat qca83xx_hw_stats[] = { + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY}, + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY}, + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD}, +}; + +struct qca83xx_priv { + u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; +}; + +MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); +MODULE_LICENSE("GPL"); + +static int qca83xx_get_sset_count(struct phy_device *phydev) +{ + return ARRAY_SIZE(qca83xx_hw_stats); +} + +static void qca83xx_get_strings(struct phy_device *phydev, u8 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) { + strscpy(data + i * ETH_GSTRING_LEN, + qca83xx_hw_stats[i].string, ETH_GSTRING_LEN); + } +} + +static u64 qca83xx_get_stat(struct phy_device *phydev, int i) +{ + struct at803x_hw_stat stat = qca83xx_hw_stats[i]; + struct qca83xx_priv *priv = phydev->priv; + int val; + u64 ret; + + if (stat.access_type == MMD) + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg); + else + val = phy_read(phydev, stat.reg); + + if (val < 0) { + ret = U64_MAX; + } else { + val = val & stat.mask; + priv->stats[i] += val; + ret = priv->stats[i]; + } + + return ret; +} + +static void qca83xx_get_stats(struct phy_device *phydev, + struct ethtool_stats *stats, u64 *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) + data[i] = qca83xx_get_stat(phydev, i); +} + +static int qca83xx_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->mdio.dev; + struct qca83xx_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + phydev->priv = priv; + + return 0; +} + +static int qca83xx_config_init(struct phy_device *phydev) +{ + u8 switch_revision; + + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK; + + switch (switch_revision) { + case 1: + /* For 100M waveform */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea); + /* Turn on Gigabit clock */ + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0); + break; + + case 2: + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0); + fallthrough; + case 4: + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860); + at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46); + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000); + break; + } + + /* Following original QCA sourcecode set port to prefer master */ + phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER); + + return 0; +} + +static int qca8327_config_init(struct phy_device *phydev) +{ + /* QCA8327 require DAC amplitude adjustment for 100m set to +6%. + * Disable on init and enable only with 100m speed following + * qca original source code. + */ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + + return qca83xx_config_init(phydev); +} + +static void qca83xx_link_change_notify(struct phy_device *phydev) +{ + /* Set DAC Amplitude adjustment to +6% for 100m on link running */ + if (phydev->state == PHY_RUNNING) { + if (phydev->speed == SPEED_100) + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, + QCA8327_DEBUG_MANU_CTRL_EN); + } else { + /* Reset DAC Amplitude adjustment */ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, + QCA8327_DEBUG_MANU_CTRL_EN, 0); + } +} + +static int qca83xx_resume(struct phy_device *phydev) +{ + int ret, val; + + /* Skip reset if not suspended */ + if (!phydev->suspended) + return 0; + + /* Reinit the port, reset values set by suspend */ + qca83xx_config_init(phydev); + + /* Reset the port on port resume */ + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); + + /* On resume from suspend the switch execute a reset and + * restart auto-negotiation. Wait for reset to complete. + */ + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), + 50000, 600000, true); + if (ret) + return ret; + + usleep_range(1000, 2000); + + return 0; +} + +static int qca83xx_suspend(struct phy_device *phydev) +{ + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN, + AT803X_DEBUG_GATE_CLK_IN1000, 0); + + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL, + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE | + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0); + + return 0; +} + +static int qca8337_suspend(struct phy_device *phydev) +{ + /* Only QCA8337 support actual suspend. */ + genphy_suspend(phydev); + + return qca83xx_suspend(phydev); +} + +static int qca8327_suspend(struct phy_device *phydev) +{ + u16 mask = 0; + + /* QCA8327 cause port unreliability when phy suspend + * is set. + */ + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX); + phy_modify(phydev, MII_BMCR, mask, 0); + + return qca83xx_suspend(phydev); +} + +static struct phy_driver qca83xx_driver[] = { +{ + /* QCA8337 */ + .phy_id = QCA8337_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8337 internal PHY", + /* PHY_GBIT_FEATURES */ + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca83xx_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8337_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-A from switch QCA8327-AL1A */ + .phy_id = QCA8327_A_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-A internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca8327_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8327_suspend, + .resume = qca83xx_resume, +}, { + /* QCA8327-B from switch QCA8327-BL1A */ + .phy_id = QCA8327_B_PHY_ID, + .phy_id_mask = QCA8K_PHY_ID_MASK, + .name = "Qualcomm Atheros 8327-B internal PHY", + /* PHY_GBIT_FEATURES */ + .link_change_notify = qca83xx_link_change_notify, + .probe = qca83xx_probe, + .flags = PHY_IS_INTERNAL, + .config_init = qca8327_config_init, + .soft_reset = genphy_soft_reset, + .get_sset_count = qca83xx_get_sset_count, + .get_strings = qca83xx_get_strings, + .get_stats = qca83xx_get_stats, + .suspend = qca8327_suspend, + .resume = qca83xx_resume, +}, }; + +module_phy_driver(qca83xx_driver); + +static struct mdio_device_id __maybe_unused qca83xx_tbl[] = { + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) }, + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, qca83xx_tbl); diff --git a/drivers/net/phy/qcom/qcom-phy-lib.c b/drivers/net/phy/qcom/qcom-phy-lib.c new file mode 100644 index 000000000000..e0295d4b4a51 --- /dev/null +++ b/drivers/net/phy/qcom/qcom-phy-lib.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/phy.h> +#include <linux/module.h> + +#include <linux/netdevice.h> +#include <linux/etherdevice.h> + +#include "qcom.h" + +MODULE_DESCRIPTION("Qualcomm PHY driver Common Functions"); +MODULE_AUTHOR("Matus Ujhelyi"); +MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); +MODULE_LICENSE("GPL"); + +int at803x_debug_reg_read(struct phy_device *phydev, u16 reg) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_read(phydev, AT803X_DEBUG_DATA); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_read); + +int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set) +{ + u16 val; + int ret; + + ret = at803x_debug_reg_read(phydev, reg); + if (ret < 0) + return ret; + + val = ret & 0xffff; + val &= ~clear; + val |= set; + + return phy_write(phydev, AT803X_DEBUG_DATA, val); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_mask); + +int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data) +{ + int ret; + + ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg); + if (ret < 0) + return ret; + + return phy_write(phydev, AT803X_DEBUG_DATA, data); +} +EXPORT_SYMBOL_GPL(at803x_debug_reg_write); + +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int ret, irq_enabled; + + if (wol->wolopts & WAKE_MAGIC) { + struct net_device *ndev = phydev->attached_dev; + const u8 *mac; + unsigned int i; + static const unsigned int offsets[] = { + AT803X_LOC_MAC_ADDR_32_47_OFFSET, + AT803X_LOC_MAC_ADDR_16_31_OFFSET, + AT803X_LOC_MAC_ADDR_0_15_OFFSET, + }; + + if (!ndev) + return -ENODEV; + + mac = (const u8 *)ndev->dev_addr; + + if (!is_valid_ether_addr(mac)) + return -EINVAL; + + for (i = 0; i < 3; i++) + phy_write_mmd(phydev, MDIO_MMD_PCS, offsets[i], + mac[(i * 2) + 1] | (mac[(i * 2)] << 8)); + + /* Enable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, 0, AT803X_INTR_ENABLE_WOL); + if (ret) + return ret; + } else { + /* Disable WOL interrupt */ + ret = phy_modify(phydev, AT803X_INTR_ENABLE, AT803X_INTR_ENABLE_WOL, 0); + if (ret) + return ret; + } + + /* Clear WOL status */ + ret = phy_read(phydev, AT803X_INTR_STATUS); + if (ret < 0) + return ret; + + /* Check if there are other interrupts except for WOL triggered when PHY is + * in interrupt mode, only the interrupts enabled by AT803X_INTR_ENABLE can + * be passed up to the interrupt PIN. + */ + irq_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (irq_enabled < 0) + return irq_enabled; + + irq_enabled &= ~AT803X_INTR_ENABLE_WOL; + if (ret & irq_enabled && !phy_polling_mode(phydev)) + phy_trigger_machine(phydev); + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_set_wol); + +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + int value; + + wol->supported = WAKE_MAGIC; + wol->wolopts = 0; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + if (value < 0) + return; + + if (value & AT803X_INTR_ENABLE_WOL) + wol->wolopts |= WAKE_MAGIC; +} +EXPORT_SYMBOL_GPL(at803x_get_wol); + +int at803x_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, AT803X_INTR_STATUS); + + return (err < 0) ? err : 0; +} +EXPORT_SYMBOL_GPL(at803x_ack_interrupt); + +int at803x_config_intr(struct phy_device *phydev) +{ + int err; + int value; + + value = phy_read(phydev, AT803X_INTR_ENABLE); + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + if (err) + return err; + + value |= AT803X_INTR_ENABLE_AUTONEG_ERR; + value |= AT803X_INTR_ENABLE_SPEED_CHANGED; + value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED; + value |= AT803X_INTR_ENABLE_LINK_FAIL; + value |= AT803X_INTR_ENABLE_LINK_SUCCESS; + + err = phy_write(phydev, AT803X_INTR_ENABLE, value); + } else { + err = phy_write(phydev, AT803X_INTR_ENABLE, 0); + if (err) + return err; + + /* Clear any pending interrupts */ + err = at803x_ack_interrupt(phydev); + } + + return err; +} +EXPORT_SYMBOL_GPL(at803x_config_intr); + +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev) +{ + int irq_status, int_enabled; + + irq_status = phy_read(phydev, AT803X_INTR_STATUS); + if (irq_status < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* Read the current enabled interrupts */ + int_enabled = phy_read(phydev, AT803X_INTR_ENABLE); + if (int_enabled < 0) { + phy_error(phydev); + return IRQ_NONE; + } + + /* See if this was one of our enabled interrupts */ + if (!(irq_status & int_enabled)) + return IRQ_NONE; + + phy_trigger_machine(phydev); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(at803x_handle_interrupt); + +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask) +{ + int ss; + + /* Read the AT8035 PHY-Specific Status register, which indicates the + * speed and duplex that the PHY is actually using, irrespective of + * whether we are in autoneg mode or not. + */ + ss = phy_read(phydev, AT803X_SPECIFIC_STATUS); + if (ss < 0) + return ss; + + if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) { + int sfc, speed; + + sfc = phy_read(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL); + if (sfc < 0) + return sfc; + + speed = ss & ss_mask.speed_mask; + speed >>= ss_mask.speed_shift; + + switch (speed) { + case AT803X_SS_SPEED_10: + phydev->speed = SPEED_10; + break; + case AT803X_SS_SPEED_100: + phydev->speed = SPEED_100; + break; + case AT803X_SS_SPEED_1000: + phydev->speed = SPEED_1000; + break; + case QCA808X_SS_SPEED_2500: + phydev->speed = SPEED_2500; + break; + } + if (ss & AT803X_SS_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (ss & AT803X_SS_MDIX) + phydev->mdix = ETH_TP_MDI_X; + else + phydev->mdix = ETH_TP_MDI; + + switch (FIELD_GET(AT803X_SFC_MDI_CROSSOVER_MODE_M, sfc)) { + case AT803X_SFC_MANUAL_MDI: + phydev->mdix_ctrl = ETH_TP_MDI; + break; + case AT803X_SFC_MANUAL_MDIX: + phydev->mdix_ctrl = ETH_TP_MDI_X; + break; + case AT803X_SFC_AUTOMATIC_CROSSOVER: + phydev->mdix_ctrl = ETH_TP_MDI_AUTO; + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_read_specific_status); + +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl) +{ + u16 val; + + switch (ctrl) { + case ETH_TP_MDI: + val = AT803X_SFC_MANUAL_MDI; + break; + case ETH_TP_MDI_X: + val = AT803X_SFC_MANUAL_MDIX; + break; + case ETH_TP_MDI_AUTO: + val = AT803X_SFC_AUTOMATIC_CROSSOVER; + break; + default: + return 0; + } + + return phy_modify_changed(phydev, AT803X_SPECIFIC_FUNCTION_CONTROL, + AT803X_SFC_MDI_CROSSOVER_MODE_M, + FIELD_PREP(AT803X_SFC_MDI_CROSSOVER_MODE_M, val)); +} +EXPORT_SYMBOL_GPL(at803x_config_mdix); + +int at803x_prepare_config_aneg(struct phy_device *phydev) +{ + int ret; + + ret = at803x_config_mdix(phydev, phydev->mdix_ctrl); + if (ret < 0) + return ret; + + /* Changes of the midx bits are disruptive to the normal operation; + * therefore any changes to these registers must be followed by a + * software reset to take effect. + */ + if (ret == 1) { + ret = genphy_soft_reset(phydev); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg); + +static int at803x_get_downshift(struct phy_device *phydev, u8 *d) +{ + int val; + + val = phy_read(phydev, AT803X_SMART_SPEED); + if (val < 0) + return val; + + if (val & AT803X_SMART_SPEED_ENABLE) + *d = FIELD_GET(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, val) + 2; + else + *d = DOWNSHIFT_DEV_DISABLE; + + return 0; +} + +static int at803x_set_downshift(struct phy_device *phydev, u8 cnt) +{ + u16 mask, set; + int ret; + + switch (cnt) { + case DOWNSHIFT_DEV_DEFAULT_COUNT: + cnt = AT803X_DEFAULT_DOWNSHIFT; + fallthrough; + case AT803X_MIN_DOWNSHIFT ... AT803X_MAX_DOWNSHIFT: + set = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER | + FIELD_PREP(AT803X_SMART_SPEED_RETRY_LIMIT_MASK, cnt - 2); + mask = AT803X_SMART_SPEED_RETRY_LIMIT_MASK; + break; + case DOWNSHIFT_DEV_DISABLE: + set = 0; + mask = AT803X_SMART_SPEED_ENABLE | + AT803X_SMART_SPEED_BYPASS_TIMER; + break; + default: + return -EINVAL; + } + + ret = phy_modify_changed(phydev, AT803X_SMART_SPEED, mask, set); + + /* After changing the smart speed settings, we need to perform a + * software reset, use phy_init_hw() to make sure we set the + * reapply any values which might got lost during software reset. + */ + if (ret == 1) + ret = phy_init_hw(phydev); + + return ret; +} + +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_get_downshift(phydev, data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_get_tunable); + +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data) +{ + switch (tuna->id) { + case ETHTOOL_PHY_DOWNSHIFT: + return at803x_set_downshift(phydev, *(const u8 *)data); + default: + return -EOPNOTSUPP; + } +} +EXPORT_SYMBOL_GPL(at803x_set_tunable); + +int at803x_cdt_fault_length(int dt) +{ + /* According to the datasheet the distance to the fault is + * DELTA_TIME * 0.824 meters. + * + * The author suspect the correct formula is: + * + * fault_distance = DELTA_TIME * (c * VF) / 125MHz / 2 + * + * where c is the speed of light, VF is the velocity factor of + * the twisted pair cable, 125MHz the counter frequency and + * we need to divide by 2 because the hardware will measure the + * round trip time to the fault and back to the PHY. + * + * With a VF of 0.69 we get the factor 0.824 mentioned in the + * datasheet. + */ + return (dt * 824) / 10; +} +EXPORT_SYMBOL_GPL(at803x_cdt_fault_length); + +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start) +{ + return phy_write(phydev, AT803X_CDT, cdt_start); +} +EXPORT_SYMBOL_GPL(at803x_cdt_start); + +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en) +{ + int val, ret; + + /* One test run takes about 25ms */ + ret = phy_read_poll_timeout(phydev, AT803X_CDT, val, + !(val & cdt_en), + 30000, 100000, true); + + return ret < 0 ? ret : 0; +} +EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion); diff --git a/drivers/net/phy/qcom/qcom.h b/drivers/net/phy/qcom/qcom.h new file mode 100644 index 000000000000..c127d8f50f0f --- /dev/null +++ b/drivers/net/phy/qcom/qcom.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10 +#define AT803X_SFC_ASSERT_CRS BIT(11) +#define AT803X_SFC_FORCE_LINK BIT(10) +#define AT803X_SFC_MDI_CROSSOVER_MODE_M GENMASK(6, 5) +#define AT803X_SFC_AUTOMATIC_CROSSOVER 0x3 +#define AT803X_SFC_MANUAL_MDIX 0x1 +#define AT803X_SFC_MANUAL_MDI 0x0 +#define AT803X_SFC_SQE_TEST BIT(2) +#define AT803X_SFC_POLARITY_REVERSAL BIT(1) +#define AT803X_SFC_DISABLE_JABBER BIT(0) + +#define AT803X_SPECIFIC_STATUS 0x11 +#define AT803X_SS_SPEED_MASK GENMASK(15, 14) +#define AT803X_SS_SPEED_1000 2 +#define AT803X_SS_SPEED_100 1 +#define AT803X_SS_SPEED_10 0 +#define AT803X_SS_DUPLEX BIT(13) +#define AT803X_SS_SPEED_DUPLEX_RESOLVED BIT(11) +#define AT803X_SS_MDIX BIT(6) + +#define QCA808X_SS_SPEED_MASK GENMASK(9, 7) +#define QCA808X_SS_SPEED_2500 4 + +#define AT803X_INTR_ENABLE 0x12 +#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15) +#define AT803X_INTR_ENABLE_SPEED_CHANGED BIT(14) +#define AT803X_INTR_ENABLE_DUPLEX_CHANGED BIT(13) +#define AT803X_INTR_ENABLE_PAGE_RECEIVED BIT(12) +#define AT803X_INTR_ENABLE_LINK_FAIL BIT(11) +#define AT803X_INTR_ENABLE_LINK_SUCCESS BIT(10) +#define AT803X_INTR_ENABLE_LINK_FAIL_BX BIT(8) +#define AT803X_INTR_ENABLE_LINK_SUCCESS_BX BIT(7) +#define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE BIT(5) +#define AT803X_INTR_ENABLE_POLARITY_CHANGED BIT(1) +#define AT803X_INTR_ENABLE_WOL BIT(0) + +#define AT803X_INTR_STATUS 0x13 + +#define AT803X_SMART_SPEED 0x14 +#define AT803X_SMART_SPEED_ENABLE BIT(5) +#define AT803X_SMART_SPEED_RETRY_LIMIT_MASK GENMASK(4, 2) +#define AT803X_SMART_SPEED_BYPASS_TIMER BIT(1) + +#define AT803X_CDT 0x16 +#define AT803X_CDT_MDI_PAIR_MASK GENMASK(9, 8) +#define AT803X_CDT_ENABLE_TEST BIT(0) +#define AT803X_CDT_STATUS 0x1c +#define AT803X_CDT_STATUS_STAT_NORMAL 0 +#define AT803X_CDT_STATUS_STAT_SHORT 1 +#define AT803X_CDT_STATUS_STAT_OPEN 2 +#define AT803X_CDT_STATUS_STAT_FAIL 3 +#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8) +#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0) + +#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C +#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B +#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A + +#define AT803X_DEBUG_ADDR 0x1D +#define AT803X_DEBUG_DATA 0x1E + +#define AT803X_DEBUG_ANALOG_TEST_CTRL 0x00 +#define QCA8327_DEBUG_MANU_CTRL_EN BIT(2) +#define QCA8337_DEBUG_MANU_CTRL_EN GENMASK(3, 2) +#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15) + +#define AT803X_DEBUG_SYSTEM_CTRL_MODE 0x05 +#define AT803X_DEBUG_TX_CLK_DLY_EN BIT(8) + +#define AT803X_DEBUG_REG_HIB_CTRL 0x0b +#define AT803X_DEBUG_HIB_CTRL_SEL_RST_80U BIT(10) +#define AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE BIT(13) +#define AT803X_DEBUG_HIB_CTRL_PS_HIB_EN BIT(15) + +#define AT803X_DEFAULT_DOWNSHIFT 5 +#define AT803X_MIN_DOWNSHIFT 2 +#define AT803X_MAX_DOWNSHIFT 9 + +enum stat_access_type { + PHY, + MMD +}; + +struct at803x_hw_stat { + const char *string; + u8 reg; + u32 mask; + enum stat_access_type access_type; +}; + +struct at803x_ss_mask { + u16 speed_mask; + u8 speed_shift; +}; + +int at803x_debug_reg_read(struct phy_device *phydev, u16 reg); +int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg, + u16 clear, u16 set); +int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data); +int at803x_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +void at803x_get_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol); +int at803x_ack_interrupt(struct phy_device *phydev); +int at803x_config_intr(struct phy_device *phydev); +irqreturn_t at803x_handle_interrupt(struct phy_device *phydev); +int at803x_read_specific_status(struct phy_device *phydev, + struct at803x_ss_mask ss_mask); +int at803x_config_mdix(struct phy_device *phydev, u8 ctrl); +int at803x_prepare_config_aneg(struct phy_device *phydev); +int at803x_get_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, void *data); +int at803x_set_tunable(struct phy_device *phydev, + struct ethtool_tunable *tuna, const void *data); +int at803x_cdt_fault_length(int dt); +int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start); +int at803x_cdt_wait_for_completion(struct phy_device *phydev, + u32 cdt_en); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 4a4f8c8e79fa..e335ece47dec 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -54,6 +54,7 @@ #include <linux/if_tun.h> #include <linux/if_vlan.h> #include <linux/crc32.h> +#include <linux/math.h> #include <linux/nsproxy.h> #include <linux/virtio_net.h> #include <linux/rcupdate.h> @@ -523,8 +524,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) { struct tun_flow_entry *e; - u32 txq = 0; - u32 numqueues = 0; + u32 txq, numqueues; numqueues = READ_ONCE(tun->numqueues); @@ -534,8 +534,7 @@ static u16 tun_automq_select_queue(struct tun_struct *tun, struct sk_buff *skb) tun_flow_save_rps_rxhash(e, txq); txq = e->queue_index; } else { - /* use multiply and shift instead of expensive divide */ - txq = ((u64)txq * numqueues) >> 32; + txq = reciprocal_scale(txq, numqueues); } return txq; diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index d837c1887416..d6168eaa286f 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -667,7 +667,7 @@ static int ax88179_set_link_ksettings(struct net_device *net, } static int -ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) +ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_keee *data) { int val; @@ -676,29 +676,29 @@ ax88179_ethtool_get_eee(struct usbnet *dev, struct ethtool_eee *data) MDIO_MMD_PCS); if (val < 0) return val; - data->supported = mmd_eee_cap_to_ethtool_sup_t(val); + data->supported_u32 = mmd_eee_cap_to_ethtool_sup_t(val); /* Get advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN); if (val < 0) return val; - data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); + data->advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); /* Get LP advertisement EEE */ val = ax88179_phy_read_mmd_indirect(dev, MDIO_AN_EEE_LPABLE, MDIO_MMD_AN); if (val < 0) return val; - data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val); + data->lp_advertised_u32 = mmd_eee_adv_to_ethtool_adv_t(val); return 0; } static int -ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_eee *data) +ax88179_ethtool_set_eee(struct usbnet *dev, struct ethtool_keee *data) { - u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised); + u16 tmp16 = ethtool_adv_to_mmd_eee_adv_t(data->advertised_u32); return ax88179_phy_write_mmd_indirect(dev, MDIO_AN_EEE_ADV, MDIO_MMD_AN, tmp16); @@ -807,7 +807,7 @@ static void ax88179_enable_eee(struct usbnet *dev) GMII_PHY_PAGE_SELECT, 2, &tmp16); } -static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) +static int ax88179_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct usbnet *dev = netdev_priv(net); struct ax88179_data *priv = dev->driver_priv; @@ -818,7 +818,7 @@ static int ax88179_get_eee(struct net_device *net, struct ethtool_eee *edata) return ax88179_ethtool_get_eee(dev, edata); } -static int ax88179_set_eee(struct net_device *net, struct ethtool_eee *edata) +static int ax88179_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct usbnet *dev = netdev_priv(net); struct ax88179_data *priv = dev->driver_priv; @@ -1587,7 +1587,7 @@ static int ax88179_reset(struct usbnet *dev) u16 *tmp16; u8 *tmp; struct ax88179_data *ax179_data = dev->driver_priv; - struct ethtool_eee eee_data; + struct ethtool_keee eee_data; tmp16 = (u16 *)buf; tmp = (u8 *)buf; @@ -1663,7 +1663,7 @@ static int ax88179_reset(struct usbnet *dev) ax88179_disable_eee(dev); ax88179_ethtool_get_eee(dev, &eee_data); - eee_data.advertised = 0; + eee_data.advertised_u32 = 0; ax88179_ethtool_set_eee(dev, &eee_data); /* Restart autoneg */ diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index a6d653ff552a..106282612bc2 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1673,7 +1673,7 @@ static int lan78xx_set_wol(struct net_device *netdev, return ret; } -static int lan78xx_get_eee(struct net_device *net, struct ethtool_eee *edata) +static int lan78xx_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct lan78xx_net *dev = netdev_priv(net); struct phy_device *phydev = net->phydev; @@ -1709,7 +1709,7 @@ exit: return ret; } -static int lan78xx_set_eee(struct net_device *net, struct ethtool_eee *edata) +static int lan78xx_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct lan78xx_net *dev = netdev_priv(net); int ret; diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 0d0672d2a654..3d806b3ff425 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -891,8 +891,8 @@ struct r8152 { void (*up)(struct r8152 *tp); void (*down)(struct r8152 *tp); void (*unload)(struct r8152 *tp); - int (*eee_get)(struct r8152 *tp, struct ethtool_eee *eee); - int (*eee_set)(struct r8152 *tp, struct ethtool_eee *eee); + int (*eee_get)(struct r8152 *tp, struct ethtool_keee *eee); + int (*eee_set)(struct r8152 *tp, struct ethtool_keee *eee); bool (*in_nway)(struct r8152 *tp); void (*hw_phy_cfg)(struct r8152 *tp); void (*autosuspend_en)(struct r8152 *tp, bool enable); @@ -8922,7 +8922,7 @@ static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) } } -static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8152_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { u32 lp, adv, supported = 0; u16 val; @@ -8938,16 +8938,16 @@ static int r8152_get_eee(struct r8152 *tp, struct ethtool_eee *eee) eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = tp->eee_adv; - eee->lp_advertised = lp; + eee->supported_u32 = supported; + eee->advertised_u32 = tp->eee_adv; + eee->lp_advertised_u32 = lp; return 0; } -static int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8152_set_eee(struct r8152 *tp, struct ethtool_keee *eee) { - u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised); + u16 val = ethtool_adv_to_mmd_eee_adv_t(eee->advertised_u32); tp->eee_en = eee->eee_enabled; tp->eee_adv = val; @@ -8957,7 +8957,7 @@ static int r8152_set_eee(struct r8152 *tp, struct ethtool_eee *eee) return 0; } -static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) +static int r8153_get_eee(struct r8152 *tp, struct ethtool_keee *eee) { u32 lp, adv, supported = 0; u16 val; @@ -8973,15 +8973,15 @@ static int r8153_get_eee(struct r8152 *tp, struct ethtool_eee *eee) eee->eee_enabled = tp->eee_en; eee->eee_active = !!(supported & adv & lp); - eee->supported = supported; - eee->advertised = tp->eee_adv; - eee->lp_advertised = lp; + eee->supported_u32 = supported; + eee->advertised_u32 = tp->eee_adv; + eee->lp_advertised_u32 = lp; return 0; } static int -rtl_ethtool_get_eee(struct net_device *net, struct ethtool_eee *edata) +rtl_ethtool_get_eee(struct net_device *net, struct ethtool_keee *edata) { struct r8152 *tp = netdev_priv(net); int ret; @@ -9008,7 +9008,7 @@ out: } static int -rtl_ethtool_set_eee(struct net_device *net, struct ethtool_eee *edata) +rtl_ethtool_set_eee(struct net_device *net, struct ethtool_keee *edata) { struct r8152 *tp = netdev_priv(net); int ret; diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h index 67b4bac048e5..c0d8fc0b22fb 100644 --- a/drivers/net/wireless/broadcom/b43/b43.h +++ b/drivers/net/wireless/broadcom/b43/b43.h @@ -1082,6 +1082,22 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev) return dev->__using_pio_transfers; } +static inline void b43_wake_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_wake_queue(dev->wl->hw, queue_prio); + else + ieee80211_wake_queue(dev->wl->hw, 0); +} + +static inline void b43_stop_queue(struct b43_wldev *dev, int queue_prio) +{ + if (dev->qos_enabled) + ieee80211_stop_queue(dev->wl->hw, queue_prio); + else + ieee80211_stop_queue(dev->wl->hw, 0); +} + /* Message printing */ __printf(2, 3) void b43info(struct b43_wl *wl, const char *fmt, ...); __printf(2, 3) void b43err(struct b43_wl *wl, const char *fmt, ...); diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c index 760d1a28edc6..6ac7dcebfff9 100644 --- a/drivers/net/wireless/broadcom/b43/dma.c +++ b/drivers/net/wireless/broadcom/b43/dma.c @@ -1399,7 +1399,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb) should_inject_overflow(ring)) { /* This TX ring is full. */ unsigned int skb_mapping = skb_get_queue_mapping(skb); - ieee80211_stop_queue(dev->wl->hw, skb_mapping); + b43_stop_queue(dev, skb_mapping); dev->wl->tx_queue_stopped[skb_mapping] = true; ring->stopped = true; if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { @@ -1570,7 +1570,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, } else { /* If the driver queue is running wake the corresponding * mac80211 queue. */ - ieee80211_wake_queue(dev->wl->hw, ring->queue_prio); + b43_wake_queue(dev, ring->queue_prio); if (b43_debug(dev, B43_DBG_DMAVERBOSE)) { b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index); } diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 92ca0b2ca286..effb6c23f825 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -2587,7 +2587,8 @@ static void b43_request_firmware(struct work_struct *work) start_ieee80211: wl->hw->queues = B43_QOS_QUEUE_NUM; - if (!modparam_qos || dev->fw.opensource) + if (!modparam_qos || dev->fw.opensource || + dev->dev->chip_id == BCMA_CHIP_ID_BCM4331) wl->hw->queues = 1; err = ieee80211_register_hw(wl->hw); @@ -3603,7 +3604,7 @@ static void b43_tx_work(struct work_struct *work) err = b43_dma_tx(dev, skb); if (err == -ENOSPC) { wl->tx_queue_stopped[queue_num] = true; - ieee80211_stop_queue(wl->hw, queue_num); + b43_stop_queue(dev, queue_num); skb_queue_head(&wl->tx_queue[queue_num], skb); break; } @@ -3627,6 +3628,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct b43_wl *wl = hw_to_b43_wl(hw); + u16 skb_queue_mapping; if (unlikely(skb->len < 2 + 2 + 6)) { /* Too short, this can't be a valid frame. */ @@ -3635,12 +3637,12 @@ static void b43_op_tx(struct ieee80211_hw *hw, } B43_WARN_ON(skb_shinfo(skb)->nr_frags); - skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); - if (!wl->tx_queue_stopped[skb->queue_mapping]) { + skb_queue_mapping = skb_get_queue_mapping(skb); + skb_queue_tail(&wl->tx_queue[skb_queue_mapping], skb); + if (!wl->tx_queue_stopped[skb_queue_mapping]) ieee80211_queue_work(wl->hw, &wl->tx_work); - } else { - ieee80211_stop_queue(wl->hw, skb->queue_mapping); - } + else + b43_stop_queue(wl->current_dev, skb_queue_mapping); } static void b43_qos_params_upload(struct b43_wldev *dev, diff --git a/drivers/net/wireless/broadcom/b43/pio.c b/drivers/net/wireless/broadcom/b43/pio.c index 0cf70fdb60a6..e41f2f5b4c26 100644 --- a/drivers/net/wireless/broadcom/b43/pio.c +++ b/drivers/net/wireless/broadcom/b43/pio.c @@ -525,7 +525,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (total_len > (q->buffer_size - q->buffer_used)) { /* Not enough memory on the queue. */ err = -EBUSY; - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; goto out; } @@ -552,7 +552,7 @@ int b43_pio_tx(struct b43_wldev *dev, struct sk_buff *skb) if (((q->buffer_size - q->buffer_used) < roundup(2 + 2 + 6, 4)) || (q->free_packet_slots == 0)) { /* The queue is full. */ - ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb)); + b43_stop_queue(dev, skb_get_queue_mapping(skb)); q->stopped = true; } @@ -587,7 +587,7 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, list_add(&pack->list, &q->packets_list); if (q->stopped) { - ieee80211_wake_queue(dev->wl->hw, q->queue_prio); + b43_wake_queue(dev, q->queue_prio); q->stopped = false; } } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c index ac3a36fa3640..f471c962104a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bca/core.c @@ -7,21 +7,33 @@ #include <core.h> #include <bus.h> #include <fwvid.h> +#include <feature.h> #include "vops.h" -static int brcmf_bca_attach(struct brcmf_pub *drvr) +#define BRCMF_BCA_E_LAST 212 + +static void brcmf_bca_feat_attach(struct brcmf_if *ifp) { - pr_err("%s: executing\n", __func__); - return 0; + /* SAE support not confirmed so disabling for now */ + ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_SAE); } -static void brcmf_bca_detach(struct brcmf_pub *drvr) +static int brcmf_bca_alloc_fweh_info(struct brcmf_pub *drvr) { - pr_err("%s: executing\n", __func__); + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_BCA_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_BCA_E_LAST; + drvr->fweh = fweh; + return 0; } const struct brcmf_fwvid_ops brcmf_bca_ops = { - .attach = brcmf_bca_attach, - .detach = brcmf_bca_detach, + .feat_attach = brcmf_bca_feat_attach, + .alloc_fweh_info = brcmf_bca_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 133c5ea6429c..736b2ada6f59 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -32,6 +32,7 @@ #include "vendor.h" #include "bus.h" #include "common.h" +#include "fwvid.h" #define BRCMF_SCAN_IE_LEN_MAX 2048 @@ -1179,8 +1180,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, scan_request = cfg->scan_request; cfg->scan_request = NULL; - if (timer_pending(&cfg->escan_timeout)) - del_timer_sync(&cfg->escan_timeout); + timer_delete_sync(&cfg->escan_timeout); if (fw_abort) { /* Do a scan abort to stop the driver's scan engine */ @@ -1687,52 +1687,39 @@ static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e) return reason; } -static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags) { struct brcmf_pub *drvr = ifp->drvr; struct brcmf_wsec_pmk_le pmk; int err; + if (key_len > sizeof(pmk.key)) { + bphy_err(drvr, "key must be less than %zu bytes\n", + sizeof(pmk.key)); + return -EINVAL; + } + memset(&pmk, 0, sizeof(pmk)); - /* pass pmk directly */ - pmk.key_len = cpu_to_le16(pmk_len); - pmk.flags = cpu_to_le16(0); - memcpy(pmk.key, pmk_data, pmk_len); + /* pass key material directly */ + pmk.key_len = cpu_to_le16(key_len); + pmk.flags = cpu_to_le16(flags); + memcpy(pmk.key, key, key_len); - /* store psk in firmware */ + /* store key material in firmware */ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_WSEC_PMK, &pmk, sizeof(pmk)); if (err < 0) bphy_err(drvr, "failed to change PSK in firmware (len=%u)\n", - pmk_len); + key_len); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_set_wsec); -static int brcmf_set_sae_password(struct brcmf_if *ifp, const u8 *pwd_data, - u16 pwd_len) +static int brcmf_set_pmk(struct brcmf_if *ifp, const u8 *pmk_data, u16 pmk_len) { - struct brcmf_pub *drvr = ifp->drvr; - struct brcmf_wsec_sae_pwd_le sae_pwd; - int err; - - if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { - bphy_err(drvr, "sae_password must be less than %d\n", - BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); - return -EINVAL; - } - - sae_pwd.key_len = cpu_to_le16(pwd_len); - memcpy(sae_pwd.key, pwd_data, pwd_len); - - err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, - sizeof(sae_pwd)); - if (err < 0) - bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", - pwd_len); - - return err; + return brcmf_set_wsec(ifp, pmk_data, pmk_len, 0); } static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason, @@ -2503,8 +2490,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "failed to clean up user-space RSNE\n"); goto done; } - err = brcmf_set_sae_password(ifp, sme->crypto.sae_pwd, - sme->crypto.sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, &sme->crypto); if (!err && sme->crypto.psk) err = brcmf_set_pmk(ifp, sme->crypto.psk, BRCMF_WSEC_MAX_PSK_LEN); @@ -3081,7 +3067,7 @@ brcmf_cfg80211_get_station_ibss(struct brcmf_if *ifp, struct brcmf_scb_val_le scbval; struct brcmf_pktcnt_le pktcnt; s32 err; - u32 rate; + u32 rate = 0; u32 rssi; /* Get the current tx rate */ @@ -5252,8 +5238,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, if (crypto->sae_pwd) { brcmf_dbg(INFO, "using SAE offload\n"); profile->use_fwauth |= BIT(BRCMF_PROFILE_FWAUTH_SAE); - err = brcmf_set_sae_password(ifp, crypto->sae_pwd, - crypto->sae_pwd_len); + err = brcmf_fwvid_set_sae_password(ifp, crypto); if (err < 0) goto exit; } @@ -5360,10 +5345,12 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, msleep(400); if (profile->use_fwauth != BIT(BRCMF_PROFILE_FWAUTH_NONE)) { + struct cfg80211_crypto_settings crypto = {}; + if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_PSK)) brcmf_set_pmk(ifp, NULL, 0); if (profile->use_fwauth & BIT(BRCMF_PROFILE_FWAUTH_SAE)) - brcmf_set_sae_password(ifp, NULL, 0); + brcmf_fwvid_set_sae_password(ifp, &crypto); profile->use_fwauth = BIT(BRCMF_PROFILE_FWAUTH_NONE); } @@ -7269,7 +7256,7 @@ static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) u32 nmode = 0; u32 vhtmode = 0; u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; - u32 rxchain; + u32 rxchain = 0; u32 nchain; int err; s32 i; @@ -8435,6 +8422,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) brcmf_btcoex_detach(cfg); wiphy_unregister(cfg->wiphy); wl_deinit_priv(cfg); + cancel_work_sync(&cfg->escan_timeout_work); brcmf_free_wiphy(cfg->wiphy); kfree(cfg); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index 0e1fa3f0dea2..dc3a6a537507 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -468,4 +468,6 @@ void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); +int brcmf_set_wsec(struct brcmf_if *ifp, const u8 *key, u16 key_len, u16 flags); + #endif /* BRCMFMAC_CFG80211_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index b6d458e022fa..b24faae35873 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -266,7 +266,7 @@ static int brcmf_c_process_cal_blob(struct brcmf_if *ifp) int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + struct brcmf_fweh_info *fweh = drvr->fweh; u8 buf[BRCMF_DCMD_SMLEN]; struct brcmf_bus *bus; struct brcmf_rev_info_le revinfo; @@ -413,15 +413,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) brcmf_c_set_joinpref_default(ifp); /* Setup event_msgs, enable E_IF */ - err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_get(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Get event_msgs error (%d)\n", err); goto done; } - setbit(eventmask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", eventmask, - BRCMF_EVENTING_MASK_LEN); + /* + * BRCMF_E_IF can safely be used to set the appropriate bit + * in the event_mask as the firmware event code is guaranteed + * to match the value of BRCMF_E_IF because it is old cruft + * that all vendors have. + */ + setbit(fweh->event_mask, BRCMF_E_IF); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) { bphy_err(drvr, "Set event_msgs error (%d)\n", err); goto done; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index f599d5f896e8..bf91b1e1368f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -691,7 +691,7 @@ static int brcmf_net_mon_open(struct net_device *ndev) { struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pub *drvr = ifp->drvr; - u32 monitor; + u32 monitor = 0; int err; brcmf_dbg(TRACE, "Enter\n"); @@ -1348,13 +1348,17 @@ int brcmf_attach(struct device *dev) goto fail; } + /* attach firmware event handler */ + ret = brcmf_fweh_attach(drvr); + if (ret != 0) { + bphy_err(drvr, "brcmf_fweh_attach failed\n"); + goto fail; + } + /* Attach to events important for core code */ brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG, brcmf_psm_watchdog_notify); - /* attach firmware event handler */ - brcmf_fweh_attach(drvr); - ret = brcmf_bus_started(drvr, drvr->ops); if (ret != 0) { bphy_err(drvr, "dongle is not responding: err=%d\n", ret); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index e4f911dd414b..ea76b8d33401 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -122,7 +122,7 @@ struct brcmf_pub { struct mutex proto_block; unsigned char proto_buf[BRCMF_DCMD_MAXLEN]; - struct brcmf_fweh_info fweh; + struct brcmf_fweh_info *fweh; struct brcmf_ampdu_rx_reorder *reorder_flows[BRCMF_AMPDU_RX_REORDER_MAXFLOWS]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index b75652ba9359..9a4837881486 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -7,21 +7,53 @@ #include <core.h> #include <bus.h> #include <fwvid.h> +#include <fwil.h> #include "vops.h" -static int brcmf_cyw_attach(struct brcmf_pub *drvr) +#define BRCMF_CYW_E_LAST 197 + +static int brcmf_cyw_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) { - pr_err("%s: executing\n", __func__); - return 0; + struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_wsec_sae_pwd_le sae_pwd; + u16 pwd_len = crypto->sae_pwd_len; + int err; + + if (pwd_len > BRCMF_WSEC_MAX_SAE_PASSWORD_LEN) { + bphy_err(drvr, "sae_password must be less than %d\n", + BRCMF_WSEC_MAX_SAE_PASSWORD_LEN); + return -EINVAL; + } + + sae_pwd.key_len = cpu_to_le16(pwd_len); + memcpy(sae_pwd.key, crypto->sae_pwd, pwd_len); + + err = brcmf_fil_iovar_data_set(ifp, "sae_password", &sae_pwd, + sizeof(sae_pwd)); + if (err < 0) + bphy_err(drvr, "failed to set SAE password in firmware (len=%u)\n", + pwd_len); + + return err; } -static void brcmf_cyw_detach(struct brcmf_pub *drvr) +static int brcmf_cyw_alloc_fweh_info(struct brcmf_pub *drvr) { - pr_err("%s: executing\n", __func__); + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_CYW_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_CYW_E_LAST; + drvr->fweh = fweh; + return 0; } const struct brcmf_fwvid_ops brcmf_cyw_ops = { - .attach = brcmf_cyw_attach, - .detach = brcmf_cyw_detach, + .set_sae_password = brcmf_cyw_set_sae_pwd, + .alloc_fweh_info = brcmf_cyw_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index 6d10c9efbe93..f23310a77a5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -13,6 +13,7 @@ #include "debug.h" #include "fwil.h" #include "fwil_types.h" +#include "fwvid.h" #include "feature.h" #include "common.h" @@ -183,7 +184,7 @@ static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, enum brcmf_feat_id id, char *name) { - u32 data; + u32 data = 0; int err; /* we need to know firmware error */ @@ -339,6 +340,11 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); + brcmf_feat_wlc_version_overrides(drvr); + brcmf_feat_firmware_overrides(drvr); + + brcmf_fwvid_feat_attach(ifp); + if (drvr->settings->feature_disable) { brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", ifp->drvr->feat_flags, @@ -346,9 +352,6 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; } - brcmf_feat_wlc_version_overrides(drvr); - brcmf_feat_firmware_overrides(drvr); - /* set chip related quirks */ switch (drvr->bus_if->chip) { case BRCM_CC_43236_CHIP_ID: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c index 68960ae98987..0774f6c59226 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c @@ -14,7 +14,8 @@ #include "fweh.h" #include "fwil.h" #include "proto.h" - +#include "bus.h" +#include "fwvid.h" /** * struct brcmf_fweh_queue_item - event item on event queue. * @@ -28,7 +29,7 @@ */ struct brcmf_fweh_queue_item { struct list_head q; - enum brcmf_fweh_event_code code; + u32 code; u8 ifidx; u8 ifaddr[ETH_ALEN]; struct brcmf_event_msg_be emsg; @@ -94,7 +95,7 @@ static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh, static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, struct brcmf_if *ifp, - enum brcmf_fweh_event_code code, + u32 fwcode, struct brcmf_event_msg *emsg, void *data) { @@ -102,13 +103,13 @@ static int brcmf_fweh_call_event_handler(struct brcmf_pub *drvr, int err = -EINVAL; if (ifp) { - fweh = &ifp->drvr->fweh; + fweh = ifp->drvr->fweh; /* handle the event if valid interface and handler */ - if (fweh->evt_handler[code]) - err = fweh->evt_handler[code](ifp, emsg, data); + if (fweh->evt_handler[fwcode]) + err = fweh->evt_handler[fwcode](ifp, emsg, data); else - bphy_err(drvr, "unhandled event %d ignored\n", code); + bphy_err(drvr, "unhandled fwevt %d ignored\n", fwcode); } else { bphy_err(drvr, "no interface object\n"); } @@ -142,7 +143,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, is_p2pdev = ((ifevent->flags & BRCMF_E_IF_FLAG_NOIF) && (ifevent->role == BRCMF_E_IF_ROLE_P2P_CLIENT || ((ifevent->role == BRCMF_E_IF_ROLE_STA) && - (drvr->fweh.p2pdev_setup_ongoing)))); + (drvr->fweh->p2pdev_setup_ongoing)))); if (!is_p2pdev && (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) { brcmf_dbg(EVENT, "event can be ignored\n"); return; @@ -163,7 +164,7 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, return; if (!is_p2pdev) brcmf_proto_add_if(drvr, ifp); - if (!drvr->fweh.evt_handler[BRCMF_E_IF]) + if (!drvr->fweh->evt_handler[BRCMF_E_IF]) if (brcmf_net_attach(ifp, false) < 0) return; } @@ -183,6 +184,45 @@ static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr, } } +static void brcmf_fweh_map_event_code(struct brcmf_fweh_info *fweh, + enum brcmf_fweh_event_code code, + u32 *fw_code) +{ + int i; + + if (WARN_ON(!fw_code)) + return; + + *fw_code = code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].code == code) { + *fw_code = fweh->event_map->items[i].fwevt_code; + break; + } + } + } +} + +static void brcmf_fweh_map_fwevt_code(struct brcmf_fweh_info *fweh, u32 fw_code, + enum brcmf_fweh_event_code *code) +{ + int i; + + if (WARN_ON(!code)) + return; + + *code = fw_code; + if (fweh->event_map) { + for (i = 0; i < fweh->event_map->n_items; i++) { + if (fweh->event_map->items[i].fwevt_code == fw_code) { + *code = fweh->event_map->items[i].code; + break; + } + } + } +} + /** * brcmf_fweh_dequeue_event() - get event from the queue. * @@ -221,15 +261,19 @@ static void brcmf_fweh_event_worker(struct work_struct *work) struct brcmf_event_msg emsg; fweh = container_of(work, struct brcmf_fweh_info, event_work); - drvr = container_of(fweh, struct brcmf_pub, fweh); + drvr = fweh->drvr; while ((event = brcmf_fweh_dequeue_event(fweh))) { - brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM\n", - brcmf_fweh_event_name(event->code), event->code, + enum brcmf_fweh_event_code code; + + brcmf_fweh_map_fwevt_code(fweh, event->code, &code); + brcmf_dbg(EVENT, "event %s (%u:%u) ifidx %u bsscfg %u addr %pM\n", + brcmf_fweh_event_name(code), code, event->code, event->emsg.ifidx, event->emsg.bsscfgidx, event->emsg.addr); if (event->emsg.bsscfgidx >= BRCMF_MAX_IFS) { - bphy_err(drvr, "invalid bsscfg index: %u\n", event->emsg.bsscfgidx); + bphy_err(drvr, "invalid bsscfg index: %u\n", + event->emsg.bsscfgidx); goto event_free; } @@ -237,7 +281,7 @@ static void brcmf_fweh_event_worker(struct work_struct *work) emsg_be = &event->emsg; emsg.version = be16_to_cpu(emsg_be->version); emsg.flags = be16_to_cpu(emsg_be->flags); - emsg.event_code = event->code; + emsg.event_code = code; emsg.status = be32_to_cpu(emsg_be->status); emsg.reason = be32_to_cpu(emsg_be->reason); emsg.auth_type = be32_to_cpu(emsg_be->auth_type); @@ -283,7 +327,7 @@ event_free: */ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) { - ifp->drvr->fweh.p2pdev_setup_ongoing = ongoing; + ifp->drvr->fweh->p2pdev_setup_ongoing = ongoing; } /** @@ -291,12 +335,27 @@ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing) * * @drvr: driver information object. */ -void brcmf_fweh_attach(struct brcmf_pub *drvr) +int brcmf_fweh_attach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh; + int err; + + err = brcmf_fwvid_alloc_fweh_info(drvr); + if (err < 0) + return err; + + fweh = drvr->fweh; + fweh->drvr = drvr; + + fweh->event_mask_len = DIV_ROUND_UP(fweh->num_event_codes, 8); + fweh->event_mask = kzalloc(fweh->event_mask_len, GFP_KERNEL); + if (!fweh->event_mask) + return -ENOMEM; + INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker); spin_lock_init(&fweh->evt_q_lock); INIT_LIST_HEAD(&fweh->event_q); + return 0; } /** @@ -306,14 +365,19 @@ void brcmf_fweh_attach(struct brcmf_pub *drvr) */ void brcmf_fweh_detach(struct brcmf_pub *drvr) { - struct brcmf_fweh_info *fweh = &drvr->fweh; + struct brcmf_fweh_info *fweh = drvr->fweh; + + if (!fweh) + return; /* cancel the worker if initialized */ if (fweh->event_work.func) { cancel_work_sync(&fweh->event_work); WARN_ON(!list_empty(&fweh->event_q)); - memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler)); } + drvr->fweh = NULL; + kfree(fweh->event_mask); + kfree(fweh); } /** @@ -326,11 +390,17 @@ void brcmf_fweh_detach(struct brcmf_pub *drvr) int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, brcmf_fweh_handler_t handler) { - if (drvr->fweh.evt_handler[code]) { + struct brcmf_fweh_info *fweh = drvr->fweh; + u32 evt_handler_idx; + + brcmf_fweh_map_event_code(fweh, code, &evt_handler_idx); + + if (fweh->evt_handler[evt_handler_idx]) { bphy_err(drvr, "event code %d already registered\n", code); return -ENOSPC; } - drvr->fweh.evt_handler[code] = handler; + + fweh->evt_handler[evt_handler_idx] = handler; brcmf_dbg(TRACE, "event handler registered for %s\n", brcmf_fweh_event_name(code)); return 0; @@ -345,9 +415,12 @@ int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, void brcmf_fweh_unregister(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code) { + u32 evt_handler_idx; + brcmf_dbg(TRACE, "event handler cleared for %s\n", brcmf_fweh_event_name(code)); - drvr->fweh.evt_handler[code] = NULL; + brcmf_fweh_map_event_code(drvr->fweh, code, &evt_handler_idx); + drvr->fweh->evt_handler[evt_handler_idx] = NULL; } /** @@ -357,27 +430,28 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr, */ int brcmf_fweh_activate_events(struct brcmf_if *ifp) { - struct brcmf_pub *drvr = ifp->drvr; + struct brcmf_fweh_info *fweh = ifp->drvr->fweh; + enum brcmf_fweh_event_code code; int i, err; - s8 eventmask[BRCMF_EVENTING_MASK_LEN]; - memset(eventmask, 0, sizeof(eventmask)); - for (i = 0; i < BRCMF_E_LAST; i++) { - if (ifp->drvr->fweh.evt_handler[i]) { + memset(fweh->event_mask, 0, fweh->event_mask_len); + for (i = 0; i < fweh->num_event_codes; i++) { + if (fweh->evt_handler[i]) { + brcmf_fweh_map_fwevt_code(fweh, i, &code); brcmf_dbg(EVENT, "enable event %s\n", - brcmf_fweh_event_name(i)); - setbit(eventmask, i); + brcmf_fweh_event_name(code)); + setbit(fweh->event_mask, i); } } /* want to handle IF event as well */ brcmf_dbg(EVENT, "enable event IF\n"); - setbit(eventmask, BRCMF_E_IF); + setbit(fweh->event_mask, BRCMF_E_IF); - err = brcmf_fil_iovar_data_set(ifp, "event_msgs", - eventmask, BRCMF_EVENTING_MASK_LEN); + err = brcmf_fil_iovar_data_set(ifp, "event_msgs", fweh->event_mask, + fweh->event_mask_len); if (err) - bphy_err(drvr, "Set event_msgs error (%d)\n", err); + bphy_err(fweh->drvr, "Set event_msgs error (%d)\n", err); return err; } @@ -397,21 +471,21 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, struct brcmf_event *event_packet, u32 packet_len, gfp_t gfp) { - enum brcmf_fweh_event_code code; - struct brcmf_fweh_info *fweh = &drvr->fweh; + u32 fwevt_idx; + struct brcmf_fweh_info *fweh = drvr->fweh; struct brcmf_fweh_queue_item *event; void *data; u32 datalen; /* get event info */ - code = get_unaligned_be32(&event_packet->msg.event_type); + fwevt_idx = get_unaligned_be32(&event_packet->msg.event_type); datalen = get_unaligned_be32(&event_packet->msg.datalen); data = &event_packet[1]; - if (code >= BRCMF_E_LAST) + if (fwevt_idx >= fweh->num_event_codes) return; - if (code != BRCMF_E_IF && !fweh->evt_handler[code]) + if (fwevt_idx != BRCMF_E_IF && !fweh->evt_handler[fwevt_idx]) return; if (datalen > BRCMF_DCMD_MAXLEN || @@ -422,13 +496,13 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr, if (!event) return; - event->datalen = datalen; - event->code = code; + event->code = fwevt_idx; event->ifidx = event_packet->msg.ifidx; /* use memcpy to get aligned event message */ memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg)); memcpy(event->data, data, datalen); + event->datalen = datalen; memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN); brcmf_fweh_queue_event(fweh, event); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h index 48414e8b9389..9ca1b2aadcb5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h @@ -17,6 +17,10 @@ struct brcmf_pub; struct brcmf_if; struct brcmf_cfg80211_info; +#define BRCMF_ABSTRACT_EVENT_BIT BIT(31) +#define BRCMF_ABSTRACT_ENUM_DEF(_id, _val) \ + BRCMF_ENUM_DEF(_id, (BRCMF_ABSTRACT_EVENT_BIT | (_val))) + /* list of firmware events */ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \ BRCMF_ENUM_DEF(SET_SSID, 0) \ @@ -98,16 +102,9 @@ struct brcmf_cfg80211_info; /* firmware event codes sent by the dongle */ enum brcmf_fweh_event_code { BRCMF_FWEH_EVENT_ENUM_DEFLIST - /* this determines event mask length which must match - * minimum length check in device firmware so it is - * hard-coded here. - */ - BRCMF_E_LAST = 139 }; #undef BRCMF_ENUM_DEF -#define BRCMF_EVENTING_MASK_LEN DIV_ROUND_UP(BRCMF_E_LAST, 8) - /* flags field values in struct brcmf_event_msg */ #define BRCMF_EVENT_MSG_LINK 0x01 #define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 @@ -288,27 +285,66 @@ typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp, void *data); /** + * struct brcmf_fweh_event_map_item - fweh event and firmware event pair. + * + * @code: fweh event code as used by higher layers. + * @fwevt_code: firmware event code as used by firmware. + * + * This mapping is needed when a functionally identical event has a + * different numerical definition between vendors. When such mapping + * is needed the higher layer event code should not collide with the + * firmware event. + */ +struct brcmf_fweh_event_map_item { + enum brcmf_fweh_event_code code; + u32 fwevt_code; +}; + +/** + * struct brcmf_fweh_event_map - mapping between firmware event and fweh event. + * + * @n_items: number of mapping items. + * @items: array of fweh event and firmware event pairs. + */ +struct brcmf_fweh_event_map { + u32 n_items; + const struct brcmf_fweh_event_map_item items[] __counted_by(n_items); +}; + +/** * struct brcmf_fweh_info - firmware event handling information. * * @p2pdev_setup_ongoing: P2P device creation in progress. * @event_work: event worker. * @evt_q_lock: lock for event queue protection. * @event_q: event queue. - * @evt_handler: registered event handlers. + * @event_mask_len: length of @event_mask used to enable firmware events. + * @event_mask: byte array used in 'event_msgs' iovar command. + * @event_map: mapping between fweh event and firmware event which + * may be provided by vendor-specific module for events that need + * mapping. + * @num_event_codes: number of firmware events supported by firmware which + * does a minimum length check for the @event_mask. This value is to + * be provided by vendor-specific module determining @event_mask_len + * and consequently the allocation size for @event_mask. + * @evt_handler: event handler registry indexed by firmware event code. */ struct brcmf_fweh_info { + struct brcmf_pub *drvr; bool p2pdev_setup_ongoing; struct work_struct event_work; spinlock_t evt_q_lock; struct list_head event_q; - int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp, - const struct brcmf_event_msg *evtmsg, - void *data); + uint event_mask_len; + u8 *event_mask; + struct brcmf_fweh_event_map *event_map; + uint num_event_codes; + brcmf_fweh_handler_t evt_handler[] __counted_by(num_event_codes); }; const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code); -void brcmf_fweh_attach(struct brcmf_pub *drvr); +int brcmf_fweh_attach(struct brcmf_pub *drvr); void brcmf_fweh_detach(struct brcmf_pub *drvr); int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code, int (*handler)(struct brcmf_if *ifp, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index 72fe8bce6eaf..bc1c6b5a6e31 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -142,6 +142,7 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_set); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) @@ -160,36 +161,7 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) return err; } - - -s32 -brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) -{ - s32 err; - __le32 data_le = cpu_to_le32(data); - - mutex_lock(&ifp->drvr->proto_block); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); - mutex_unlock(&ifp->drvr->proto_block); - - return err; -} - -s32 -brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) -{ - s32 err; - __le32 data_le = cpu_to_le32(*data); - - mutex_lock(&ifp->drvr->proto_block); - err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); - mutex_unlock(&ifp->drvr->proto_block); - *data = le32_to_cpu(data_le); - brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); - - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_cmd_data_get); static u32 brcmf_create_iovar(const char *name, const char *data, u32 datalen, @@ -239,6 +211,7 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *dat mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_set); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, @@ -270,26 +243,7 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); -} - -s32 -brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_iovar_data_get); static u32 brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen, @@ -364,6 +318,7 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_set); s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, @@ -394,28 +349,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, mutex_unlock(&drvr->proto_block); return err; } - -s32 -brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, - sizeof(data_le)); -} - -s32 -brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, - sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_bsscfg_data_get); static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len, char *buf, u32 buflen) @@ -465,6 +399,7 @@ s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_set); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len) @@ -494,39 +429,4 @@ s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, mutex_unlock(&drvr->proto_block); return err; } - -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data) -{ - __le32 data_le = cpu_to_le32(data); - - return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, - sizeof(data_le)); -} - -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data) -{ - __le32 data_le = cpu_to_le32(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le32_to_cpu(data_le); - return err; -} - -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data) -{ - return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); -} - -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data) -{ - __le16 data_le = cpu_to_le16(*data); - s32 err; - - err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); - if (err == 0) - *data = le16_to_cpu(data_le); - return err; -} - +BRCMF_EXPORT_SYMBOL_GPL(brcmf_fil_xtlv_data_get);
\ No newline at end of file diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h index bc693157c4b1..a315a7fac6a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h @@ -81,29 +81,122 @@ s32 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); s32 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len); -s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data); -s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data); +static inline +s32 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) +{ + s32 err; + __le32 data_le = cpu_to_le32(data); -s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data, - u32 len); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); + err = brcmf_fil_cmd_data_set(ifp, cmd, &data_le, sizeof(data_le)); + + return err; +} +static inline +s32 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) +{ + s32 err; + __le32 data_le = cpu_to_le32(*data); + + err = brcmf_fil_cmd_data_get(ifp, cmd, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); + + return err; +} + +s32 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, + const void *data, u32 len); s32 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data, u32 len); -s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data); - -s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, void *data, - u32 len); -s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data); -s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data); +static inline +s32 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); +} +static inline +s32 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + + +s32 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +s32 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name, + void *data, u32 len); +static inline +s32 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, + sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} + s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id, void *data, u32 len); -s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data); -s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data); -s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data); -s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data); +static inline +s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, + u32 data) +{ + __le32 data_le = cpu_to_le32(data); + + return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le, + sizeof(data_le)); +} +static inline +s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, + u32 *data) +{ + __le32 data_le = cpu_to_le32(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le32_to_cpu(data_le); + return err; +} +static inline +s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, + u8 *data) +{ + return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data)); +} +static inline +s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, + u16 *data) +{ + __le16 data_le = cpu_to_le16(*data); + s32 err; + + err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le)); + if (err == 0) + *data = le16_to_cpu(data_le); + return err; +} #endif /* _fwil_h_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h index 9d248ba1c0b2..e74a23e11830 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil_types.h @@ -584,7 +584,7 @@ struct brcmf_wsec_key_le { struct brcmf_wsec_pmk_le { __le16 key_len; __le16 flags; - u8 key[2 * BRCMF_WSEC_MAX_PSK_LEN + 1]; + u8 key[BRCMF_WSEC_MAX_SAE_PASSWORD_LEN]; }; /** diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c index 86eafdb40541..41eafcda77f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.c @@ -90,7 +90,7 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod, return -ERANGE; if (WARN_ON(!vmod) || WARN_ON(!vops) || - WARN_ON(!vops->attach) || WARN_ON(!vops->detach)) + WARN_ON(!vops->alloc_fweh_info)) return -EINVAL; if (WARN_ON(fwvid_list[fwvid].vmod)) @@ -150,7 +150,7 @@ static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid) } #endif -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) +int brcmf_fwvid_attach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; int ret; @@ -175,7 +175,7 @@ int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr) return ret; } -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr) +void brcmf_fwvid_detach(struct brcmf_pub *drvr) { enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid; @@ -187,9 +187,10 @@ void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr) mutex_lock(&fwvid_list_lock); - drvr->vops = NULL; - list_del(&drvr->bus_if->list); - + if (drvr->vops) { + drvr->vops = NULL; + list_del(&drvr->bus_if->list); + } mutex_unlock(&fwvid_list_lock); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h index 43df58bb70ad..e6ac9fc341bc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwvid.h @@ -6,12 +6,15 @@ #define FWVID_H_ #include "firmware.h" +#include "cfg80211.h" struct brcmf_pub; +struct brcmf_if; struct brcmf_fwvid_ops { - int (*attach)(struct brcmf_pub *drvr); - void (*detach)(struct brcmf_pub *drvr); + void (*feat_attach)(struct brcmf_if *ifp); + int (*set_sae_password)(struct brcmf_if *ifp, struct cfg80211_crypto_settings *crypto); + int (*alloc_fweh_info)(struct brcmf_pub *drvr); }; /* exported functions */ @@ -20,28 +23,37 @@ int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *mod, int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod); /* core driver functions */ -int brcmf_fwvid_attach_ops(struct brcmf_pub *drvr); -void brcmf_fwvid_detach_ops(struct brcmf_pub *drvr); +int brcmf_fwvid_attach(struct brcmf_pub *drvr); +void brcmf_fwvid_detach(struct brcmf_pub *drvr); const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr); -static inline int brcmf_fwvid_attach(struct brcmf_pub *drvr) +static inline void brcmf_fwvid_feat_attach(struct brcmf_if *ifp) { - int ret; + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; - ret = brcmf_fwvid_attach_ops(drvr); - if (ret) - return ret; + if (!vops->feat_attach) + return; - return drvr->vops->attach(drvr); + vops->feat_attach(ifp); } -static inline void brcmf_fwvid_detach(struct brcmf_pub *drvr) +static inline int brcmf_fwvid_set_sae_password(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) +{ + const struct brcmf_fwvid_ops *vops = ifp->drvr->vops; + + if (!vops || !vops->set_sae_password) + return -EOPNOTSUPP; + + return vops->set_sae_password(ifp, crypto); +} + +static inline int brcmf_fwvid_alloc_fweh_info(struct brcmf_pub *drvr) { if (!drvr->vops) - return; + return -EIO; - drvr->vops->detach(drvr); - brcmf_fwvid_detach_ops(drvr); + return drvr->vops->alloc_fweh_info(drvr); } #endif /* FWVID_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c index 5573a47766ad..05d7c2a4fba5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/wcc/core.c @@ -7,21 +7,34 @@ #include <core.h> #include <bus.h> #include <fwvid.h> +#include <cfg80211.h> #include "vops.h" -static int brcmf_wcc_attach(struct brcmf_pub *drvr) +#define BRCMF_WCC_E_LAST 213 + +static int brcmf_wcc_set_sae_pwd(struct brcmf_if *ifp, + struct cfg80211_crypto_settings *crypto) { - pr_debug("%s: executing\n", __func__); - return 0; + return brcmf_set_wsec(ifp, crypto->sae_pwd, crypto->sae_pwd_len, + BRCMF_WSEC_PASSPHRASE); } -static void brcmf_wcc_detach(struct brcmf_pub *drvr) +static int brcmf_wcc_alloc_fweh_info(struct brcmf_pub *drvr) { - pr_debug("%s: executing\n", __func__); + struct brcmf_fweh_info *fweh; + + fweh = kzalloc(struct_size(fweh, evt_handler, BRCMF_WCC_E_LAST), + GFP_KERNEL); + if (!fweh) + return -ENOMEM; + + fweh->num_event_codes = BRCMF_WCC_E_LAST; + drvr->fweh = fweh; + return 0; } const struct brcmf_fwvid_ops brcmf_wcc_ops = { - .attach = brcmf_wcc_attach, - .detach = brcmf_wcc_detach, + .set_sae_password = brcmf_wcc_set_sae_pwd, + .alloc_fweh_info = brcmf_wcc_alloc_fweh_info, }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index ccc621b8ed9f..07f83ff5a54a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -551,8 +551,7 @@ wlc_phy_attach(struct shared_phy *sh, struct bcma_device *d11core, if (!pi->phycal_timer) goto err; - if (!wlc_phy_attach_nphy(pi)) - goto err; + wlc_phy_attach_nphy(pi); } else if (ISLCNPHY(pi)) { if (!wlc_phy_attach_lcnphy(pi)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 8668fa5558a2..70a9ec050717 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -941,7 +941,7 @@ void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag); void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); -bool wlc_phy_attach_nphy(struct brcms_phy *pi); +void wlc_phy_attach_nphy(struct brcms_phy *pi); bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); void wlc_phy_detach_lcnphy(struct brcms_phy *pi); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index 8580a2754789..cd9b502a6a9f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -14546,7 +14546,7 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) wlc_phy_txpwr_apply_nphy(pi); } -static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) +static void wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) { struct ssb_sprom *sprom = &pi->d11core->bus->sprom; @@ -14595,11 +14595,9 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) pi->phycal_tempdelta = 0; wlc_phy_txpwr_srom_read_ppr_nphy(pi); - - return true; } -bool wlc_phy_attach_nphy(struct brcms_phy *pi) +void wlc_phy_attach_nphy(struct brcms_phy *pi) { uint i; @@ -14645,10 +14643,7 @@ bool wlc_phy_attach_nphy(struct brcms_phy *pi) pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy; pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy; - if (!wlc_phy_txpwr_srom_read_nphy(pi)) - return false; - - return true; + wlc_phy_txpwr_srom_read_nphy(pi); } static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn) diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 17570d62c896..9d33a66a49b5 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -3438,9 +3438,7 @@ il_init_geos(struct il_priv *il) if (!channels) return -ENOMEM; - rates = - kzalloc((sizeof(struct ieee80211_rate) * RATE_COUNT_LEGACY), - GFP_KERNEL); + rates = kcalloc(RATE_COUNT_LEGACY, sizeof(*rates), GFP_KERNEL); if (!rates) { kfree(channels); return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 3604abcbcff9..b909a7665e9c 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -3359,7 +3359,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, } if (!wowlan->patterns[i].pkt_offset) { - if (!(byte_seq[0] & 0x01) && + if (is_unicast_ether_addr(byte_seq) && (byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] == 1)) { mef_cfg->criteria |= MWIFIEX_CRITERIA_UNICAST; continue; diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index f9c9fec7c792..d14a0f4c1b6d 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -970,9 +970,6 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv) priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, mwifiex_dfs_dir); - if (!priv->dfs_dev_dir) - return; - MWIFIEX_DFS_ADD_FILE(info); MWIFIEX_DFS_ADD_FILE(debug); MWIFIEX_DFS_ADD_FILE(getlog); diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 00a5679b5c51..8558995e8fc7 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -871,7 +871,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, } } else { memcpy(ra, skb->data, ETH_ALEN); - if (ra[0] & 0x01 || mwifiex_is_skb_mgmt_frame(skb)) + if (is_multicast_ether_addr(ra) || mwifiex_is_skb_mgmt_frame(skb)) eth_broadcast_addr(ra); ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); } diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index ad2509d8c99a..f03fd15c0c97 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1609,7 +1609,6 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) cfg80211_unregister_netdevice(vif->ndev); vif->monitor_flag = 0; - wilc_set_operation_mode(vif, 0, 0, 0); mutex_lock(&wl->vif_mutex); list_del_rcu(&vif->list); wl->vif_num--; @@ -1804,15 +1803,24 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, INIT_LIST_HEAD(&wl->rxq_head.list); INIT_LIST_HEAD(&wl->vif_list); + wl->hif_workqueue = alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, + wiphy_name(wl->wiphy)); + if (!wl->hif_workqueue) { + ret = -ENOMEM; + goto free_cfg; + } vif = wilc_netdev_ifc_init(wl, "wlan%d", WILC_STATION_MODE, NL80211_IFTYPE_STATION, false); if (IS_ERR(vif)) { ret = PTR_ERR(vif); - goto free_cfg; + goto free_hq; } return 0; +free_hq: + destroy_workqueue(wl->hif_workqueue); + free_cfg: wilc_wlan_cfg_deinit(wl); diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index 839f142663e8..d2b8c2630819 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -377,38 +377,49 @@ struct wilc_join_bss_param * wilc_parse_join_bss_param(struct cfg80211_bss *bss, struct cfg80211_crypto_settings *crypto) { - struct wilc_join_bss_param *param; - struct ieee80211_p2p_noa_attr noa_attr; - u8 rates_len = 0; - const u8 *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; + const u8 *ies_data, *tim_elm, *ssid_elm, *rates_ie, *supp_rates_ie; const u8 *ht_ie, *wpa_ie, *wmm_ie, *rsn_ie; + struct ieee80211_p2p_noa_attr noa_attr; + const struct cfg80211_bss_ies *ies; + struct wilc_join_bss_param *param; + u8 rates_len = 0, ies_len; int ret; - const struct cfg80211_bss_ies *ies = rcu_dereference(bss->ies); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) return NULL; + rcu_read_lock(); + ies = rcu_dereference(bss->ies); + ies_data = kmemdup(ies->data, ies->len, GFP_ATOMIC); + if (!ies_data) { + rcu_read_unlock(); + kfree(param); + return NULL; + } + ies_len = ies->len; + rcu_read_unlock(); + param->beacon_period = cpu_to_le16(bss->beacon_interval); param->cap_info = cpu_to_le16(bss->capability); param->bss_type = WILC_FW_BSS_TYPE_INFRA; param->ch = ieee80211_frequency_to_channel(bss->channel->center_freq); ether_addr_copy(param->bssid, bss->bssid); - ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len); + ssid_elm = cfg80211_find_ie(WLAN_EID_SSID, ies_data, ies_len); if (ssid_elm) { if (ssid_elm[1] <= IEEE80211_MAX_SSID_LEN) memcpy(param->ssid, ssid_elm + 2, ssid_elm[1]); } - tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies->data, ies->len); + tim_elm = cfg80211_find_ie(WLAN_EID_TIM, ies_data, ies_len); if (tim_elm && tim_elm[1] >= 2) param->dtim_period = tim_elm[3]; memset(param->p_suites, 0xFF, 3); memset(param->akm_suites, 0xFF, 3); - rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); + rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies_data, ies_len); if (rates_ie) { rates_len = rates_ie[1]; if (rates_len > WILC_MAX_RATES_SUPPORTED) @@ -419,7 +430,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, if (rates_len < WILC_MAX_RATES_SUPPORTED) { supp_rates_ie = cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES, - ies->data, ies->len); + ies_data, ies_len); if (supp_rates_ie) { u8 ext_rates = supp_rates_ie[1]; @@ -434,11 +445,11 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } } - ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies->data, ies->len); + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies_data, ies_len); if (ht_ie) param->ht_capable = true; - ret = cfg80211_get_p2p_attr(ies->data, ies->len, + ret = cfg80211_get_p2p_attr(ies_data, ies_len, IEEE80211_P2P_ATTR_ABSENCE_NOTICE, (u8 *)&noa_attr, sizeof(noa_attr)); if (ret > 0) { @@ -462,7 +473,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, } wmm_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WMM, - ies->data, ies->len); + ies_data, ies_len); if (wmm_ie) { struct ieee80211_wmm_param_ie *ie; @@ -477,13 +488,13 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, wpa_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, - ies->data, ies->len); + ies_data, ies_len); if (wpa_ie) { param->mode_802_11i = 1; param->rsn_found = true; } - rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies->data, ies->len); + rsn_ie = cfg80211_find_ie(WLAN_EID_RSN, ies_data, ies_len); if (rsn_ie) { int rsn_ie_len = sizeof(struct element) + rsn_ie[1]; int offset = 8; @@ -517,6 +528,7 @@ wilc_parse_join_bss_param(struct cfg80211_bss *bss, param->akm_suites[i] = crypto->akm_suites[i] & 0xFF; } + kfree(ies_data); return (void *)param; } diff --git a/drivers/net/wireless/microchip/wilc1000/netdev.c b/drivers/net/wireless/microchip/wilc1000/netdev.c index 91d71e0f7ef2..3be3c1754770 100644 --- a/drivers/net/wireless/microchip/wilc1000/netdev.c +++ b/drivers/net/wireless/microchip/wilc1000/netdev.c @@ -416,7 +416,7 @@ static int wilc_init_fw_config(struct net_device *dev, struct wilc_vif *vif) b = 1; if (!wilc_wlan_cfg_set(vif, 0, WID_11N_IMMEDIATE_BA_ENABLED, &b, 1, - 1, 1)) + 1, 0)) goto fail; return 0; @@ -989,13 +989,6 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, goto error; } - wl->hif_workqueue = alloc_ordered_workqueue("%s-wq", WQ_MEM_RECLAIM, - ndev->name); - if (!wl->hif_workqueue) { - ret = -ENOMEM; - goto unregister_netdev; - } - ndev->needs_free_netdev = true; vif->iftype = vif_type; vif->idx = wilc_get_available_idx(wl); @@ -1008,12 +1001,11 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, return vif; -unregister_netdev: +error: if (rtnl_locked) cfg80211_unregister_netdevice(ndev); else unregister_netdev(ndev); - error: free_netdev(ndev); return ERR_PTR(ret); } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 9eb115c79c90..6b2f2269ddf8 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1198,27 +1198,32 @@ int wilc_wlan_stop(struct wilc *wilc, struct wilc_vif *vif) acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); - ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); - if (ret) { - netdev_err(vif->ndev, "Error while reading reg\n"); + ret = wilc->hif_func->hif_read_reg(wilc, GLOBAL_MODE_CONTROL, ®); + if (ret) goto release; - } - ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, - (reg | WILC_ABORT_REQ_BIT)); - if (ret) { - netdev_err(vif->ndev, "Error while writing reg\n"); + reg &= ~WILC_GLOBAL_MODE_ENABLE_WIFI; + ret = wilc->hif_func->hif_write_reg(wilc, GLOBAL_MODE_CONTROL, reg); + if (ret) + goto release; + + ret = wilc->hif_func->hif_read_reg(wilc, PWR_SEQ_MISC_CTRL, ®); + if (ret) + goto release; + + reg &= ~WILC_PWR_SEQ_ENABLE_WIFI_SLEEP; + ret = wilc->hif_func->hif_write_reg(wilc, PWR_SEQ_MISC_CTRL, reg); + if (ret) goto release; - } - ret = wilc->hif_func->hif_read_reg(wilc, WILC_FW_HOST_COMM, ®); + ret = wilc->hif_func->hif_read_reg(wilc, WILC_GP_REG_0, ®); if (ret) { netdev_err(vif->ndev, "Error while reading reg\n"); goto release; } - reg = BIT(0); - ret = wilc->hif_func->hif_write_reg(wilc, WILC_FW_HOST_COMM, reg); + ret = wilc->hif_func->hif_write_reg(wilc, WILC_GP_REG_0, + (reg | WILC_ABORT_REQ_BIT)); if (ret) { netdev_err(vif->ndev, "Error while writing reg\n"); goto release; @@ -1410,7 +1415,7 @@ static int init_chip(struct net_device *dev) struct wilc_vif *vif = netdev_priv(dev); struct wilc *wilc = vif->wilc; - acquire_bus(wilc, WILC_BUS_ACQUIRE_ONLY); + acquire_bus(wilc, WILC_BUS_ACQUIRE_AND_WAKEUP); chipid = wilc_get_chipid(wilc, true); @@ -1440,7 +1445,7 @@ static int init_chip(struct net_device *dev) } release: - release_bus(wilc, WILC_BUS_RELEASE_ONLY); + release_bus(wilc, WILC_BUS_RELEASE_ALLOW_SLEEP); return ret; } diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.h b/drivers/net/wireless/microchip/wilc1000/wlan.h index a72cd5cac81d..f02775f7e41f 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan.h @@ -156,6 +156,12 @@ #define WILC_GP_REG_0 0x149c #define WILC_GP_REG_1 0x14a0 +#define GLOBAL_MODE_CONTROL 0x1614 +#define PWR_SEQ_MISC_CTRL 0x3008 + +#define WILC_GLOBAL_MODE_ENABLE_WIFI BIT(0) +#define WILC_PWR_SEQ_ENABLE_WIFI_SLEEP BIT(28) + #define WILC_HAVE_SDIO_IRQ_GPIO BIT(0) #define WILC_HAVE_USE_PMU BIT(1) #define WILC_HAVE_SLEEP_CLK_SRC_RTC BIT(2) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c b/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c index ad95f9eba301..1000fbfb94b8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00crypto.c @@ -197,10 +197,7 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, transfer += header_length; } else { skb_push(skb, iv_len + align); - if (align < icv_len) - skb_put(skb, icv_len - align); - else if (align > icv_len) - skb_trim(skb, rxdesc->size + iv_len + icv_len); + skb_put(skb, icv_len - align); /* Move ieee80211 header */ memmove(skb->data + transfer, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h index 4695fb4e2d2d..03307da67c2c 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h @@ -498,6 +498,7 @@ struct rtl8xxxu_txdesc40 { #define DESC_RATE_ID_SHIFT 16 #define DESC_RATE_ID_MASK 0xf #define TXDESC_NAVUSEHDR BIT(20) +#define TXDESC_EN_DESC_ID BIT(21) #define TXDESC_SEC_RC4 0x00400000 #define TXDESC_SEC_AES 0x00c00000 #define TXDESC_PKT_OFFSET_SHIFT 26 @@ -1774,6 +1775,8 @@ struct rtl8xxxu_cfo_tracking { #define RTL8XXXU_HW_LED_CONTROL 2 #define RTL8XXXU_MAX_MAC_ID_NUM 128 #define RTL8XXXU_BC_MC_MACID 0 +#define RTL8XXXU_BC_MC_MACID1 1 +#define RTL8XXXU_MAX_SEC_CAM_NUM 64 struct rtl8xxxu_priv { struct ieee80211_hw *hw; @@ -1892,15 +1895,12 @@ struct rtl8xxxu_priv { u8 rssi_level; DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS); DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS); - /* - * Only one virtual interface permitted because only STA mode - * is supported and no iface_combinations are provided. - */ - struct ieee80211_vif *vif; + + struct ieee80211_vif *vifs[2]; struct delayed_work ra_watchdog; struct work_struct c2hcmd_work; struct sk_buff_head c2hcmd_queue; - struct work_struct update_beacon_work; + struct delayed_work update_beacon_work; struct rtl8xxxu_btcoex bt_coex; struct rtl8xxxu_ra_report ra_report; struct rtl8xxxu_cfo_tracking cfo_tracking; @@ -1910,6 +1910,7 @@ struct rtl8xxxu_priv { char led_name[32]; struct led_classdev led_cdev; DECLARE_BITMAP(mac_id_map, RTL8XXXU_MAX_MAC_ID_NUM); + DECLARE_BITMAP(cam_map, RTL8XXXU_MAX_SEC_CAM_NUM); }; struct rtl8xxxu_sta_info { @@ -1919,6 +1920,11 @@ struct rtl8xxxu_sta_info { u8 macid; }; +struct rtl8xxxu_vif { + int port_num; + u8 hw_key_idx; +}; + struct rtl8xxxu_rx_urb { struct urb urb; struct ieee80211_hw *hw; @@ -1986,11 +1992,13 @@ struct rtl8xxxu_fileops { u8 init_reg_rxfltmap:1; u8 init_reg_pkt_life_time:1; u8 init_reg_hmtfr:1; + u8 supports_concurrent:1; u8 ampdu_max_time; u8 ustime_tsf_edca; u16 max_aggr_num; u8 supports_ap:1; u16 max_macid_num; + u16 max_sec_cam_num; u32 adda_1t_init; u32 adda_1t_path_on; u32 adda_2t_path_on_a; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c index 6d0f975f891b..afe9cc1b49dc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188e.c @@ -1699,7 +1699,7 @@ void rtl8188e_handle_ra_tx_report2(struct rtl8xxxu_priv *priv, struct sk_buff *s /* We only use macid 0, so only the first item is relevant. * AP mode will use more of them if it's ever implemented. */ - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION) + if (!priv->vifs[0] || priv->vifs[0]->type == NL80211_IFTYPE_STATION) items = 1; for (macid = 0; macid < items; macid++) { @@ -1882,6 +1882,7 @@ struct rtl8xxxu_fileops rtl8188eu_fops = { .has_tx_report = 1, .init_reg_pkt_life_time = 1, .gen2_thermal_meter = 1, + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, /* diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c index 1e1c8fa194cb..464216d007ce 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8188f.c @@ -1751,6 +1751,8 @@ struct rtl8xxxu_fileops rtl8188fu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 16, + .max_sec_cam_num = 16, + .supports_concurrent = 1, .adda_1t_init = 0x03c00014, .adda_1t_path_on = 0x03c00014, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c index b30a9a513cb8..3ee7d8f87da6 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192c.c @@ -613,6 +613,7 @@ struct rtl8xxxu_fileops rtl8192cu_fops = { .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c index 47bcaec6f2db..63b73ace27ec 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192e.c @@ -1769,6 +1769,7 @@ struct rtl8xxxu_fileops rtl8192eu_fops = { .needs_full_init = 1, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .adda_1t_init = 0x0fc01616, .adda_1t_path_on = 0x0fc01616, .adda_2t_path_on_a = 0x0fc01616, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c index 28e93835e05a..21e4204769d0 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8192f.c @@ -2014,26 +2014,40 @@ static int rtl8192fu_led_brightness_set(struct led_classdev *led_cdev, struct rtl8xxxu_priv *priv = container_of(led_cdev, struct rtl8xxxu_priv, led_cdev); - u16 ledcfg; + u32 ledcfg; /* Values obtained by observing the USB traffic from the Windows driver. */ rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_0, 0x20080); rtl8xxxu_write32(priv, REG_SW_GPIO_SHARE_CTRL_1, 0x1b0000); - ledcfg = rtl8xxxu_read16(priv, REG_LEDCFG0); + ledcfg = rtl8xxxu_read32(priv, REG_LEDCFG0); + + /* Comfast CF-826F uses LED1. Asus USB-N13 C1 uses LED0. Set both. */ + + u32p_replace_bits(&ledcfg, LED_GPIO_ENABLE, LEDCFG0_LED2EN); + u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED0_IO_MODE); + u32p_replace_bits(&ledcfg, LED_IO_MODE_OUTPUT, LEDCFG0_LED1_IO_MODE); if (brightness == LED_OFF) { - /* Value obtained like above. */ - ledcfg = BIT(1) | BIT(7); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV); } else if (brightness == LED_ON) { - /* Value obtained like above. */ - ledcfg = BIT(1) | BIT(7) | BIT(11); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_SW_CTRL, LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_ON, LEDCFG0_LED1SV); } else if (brightness == RTL8XXXU_HW_LED_CONTROL) { - /* Value obtained by brute force. */ - ledcfg = BIT(8) | BIT(9); + u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS, + LEDCFG0_LED0CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED0SV); + u32p_replace_bits(&ledcfg, LED_MODE_TX_OR_RX_EVENTS, + LEDCFG0_LED1CM); + u32p_replace_bits(&ledcfg, LED_SW_OFF, LEDCFG0_LED1SV); } - rtl8xxxu_write16(priv, REG_LEDCFG0, ledcfg); + rtl8xxxu_write32(priv, REG_LEDCFG0, ledcfg); return 0; } @@ -2081,6 +2095,7 @@ struct rtl8xxxu_fileops rtl8192fu_fops = { .max_aggr_num = 0x1f1f, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .trxff_boundary = 0x3f3f, .pbp_rx = PBP_PAGE_SIZE_256, .pbp_tx = PBP_PAGE_SIZE_256, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c index 871b8cca8a18..46d57510e9fc 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8710b.c @@ -1877,6 +1877,7 @@ struct rtl8xxxu_fileops rtl8710bu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 16, + .max_sec_cam_num = 32, .adda_1t_init = 0x03c00016, .adda_1t_path_on = 0x03c00016, .trxff_boundary = 0x3f7f, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c index 15a30e496221..ad1bb9377ca2 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723a.c @@ -510,6 +510,7 @@ struct rtl8xxxu_fileops rtl8723au_fops = { .rx_agg_buf_size = 16000, .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32), .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16), + .max_sec_cam_num = 32, .adda_1t_init = 0x0b1b25a0, .adda_1t_path_on = 0x0bdb25a0, .adda_2t_path_on_a = 0x04db25a4, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c index 954369ed6226..9640c841d20a 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_8723b.c @@ -1744,6 +1744,7 @@ struct rtl8xxxu_fileops rtl8723bu_fops = { .max_aggr_num = 0x0c14, .supports_ap = 1, .max_macid_num = 128, + .max_sec_cam_num = 64, .adda_1t_init = 0x01c00014, .adda_1t_path_on = 0x01c00014, .adda_2t_path_on_a = 0x01c00014, diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c index 180907319e8c..3b954c2fe448 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c @@ -1633,33 +1633,41 @@ rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40) } static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv, - enum nl80211_iftype linktype) + enum nl80211_iftype linktype, int port_num) { - u8 val8; - - val8 = rtl8xxxu_read8(priv, REG_MSR); - val8 &= ~MSR_LINKTYPE_MASK; + u8 val8, type; switch (linktype) { case NL80211_IFTYPE_UNSPECIFIED: - val8 |= MSR_LINKTYPE_NONE; + type = MSR_LINKTYPE_NONE; break; case NL80211_IFTYPE_ADHOC: - val8 |= MSR_LINKTYPE_ADHOC; + type = MSR_LINKTYPE_ADHOC; break; case NL80211_IFTYPE_STATION: - val8 |= MSR_LINKTYPE_STATION; + type = MSR_LINKTYPE_STATION; break; case NL80211_IFTYPE_AP: - val8 |= MSR_LINKTYPE_AP; + type = MSR_LINKTYPE_AP; break; default: - goto out; + return; + } + + switch (port_num) { + case 0: + val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x0c; + val8 |= type; + break; + case 1: + val8 = rtl8xxxu_read8(priv, REG_MSR) & 0x03; + val8 |= type << 2; + break; + default: + return; } rtl8xxxu_write8(priv, REG_MSR, val8); -out: - return; } static void @@ -3572,27 +3580,47 @@ void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv) rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00); } -static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv) +static int rtl8xxxu_set_mac(struct rtl8xxxu_priv *priv, int port_num) { int i; u16 reg; - reg = REG_MACID; + switch (port_num) { + case 0: + reg = REG_MACID; + break; + case 1: + reg = REG_MACID1; + break; + default: + WARN_ONCE("%s: invalid port_num\n", __func__); + return -EINVAL; + } for (i = 0; i < ETH_ALEN; i++) - rtl8xxxu_write8(priv, reg + i, priv->mac_addr[i]); + rtl8xxxu_write8(priv, reg + i, priv->vifs[port_num]->addr[i]); return 0; } -static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid) +static int rtl8xxxu_set_bssid(struct rtl8xxxu_priv *priv, const u8 *bssid, int port_num) { int i; u16 reg; dev_dbg(&priv->udev->dev, "%s: (%pM)\n", __func__, bssid); - reg = REG_BSSID; + switch (port_num) { + case 0: + reg = REG_BSSID; + break; + case 1: + reg = REG_BSSID1; + break; + default: + WARN_ONCE("%s: invalid port_num\n", __func__); + return -EINVAL; + } for (i = 0; i < ETH_ALEN; i++) rtl8xxxu_write8(priv, reg + i, bssid[i]); @@ -4025,10 +4053,13 @@ static inline u8 rtl8xxxu_get_macid(struct rtl8xxxu_priv *priv, { struct rtl8xxxu_sta_info *sta_info; - if (!priv->vif || priv->vif->type == NL80211_IFTYPE_STATION || !sta) + if (!sta) return 0; sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + if (!sta_info) + return 0; + return sta_info->macid; } @@ -4235,9 +4266,6 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff); } - rtl8xxxu_set_mac(priv); - rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION); - /* * Configure initial WMAC settings */ @@ -4511,6 +4539,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw) rtl8188e_ra_info_init_all(&priv->ra_info); set_bit(RTL8XXXU_BC_MC_MACID, priv->mac_id_map); + set_bit(RTL8XXXU_BC_MC_MACID1, priv->mac_id_map); exit: return ret; @@ -4530,8 +4559,10 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, * This is a bit of a hack - the lower bits of the cipher * suite selector happens to match the cipher index in the CAM */ - addr = key->keyidx << CAM_CMD_KEY_SHIFT; + addr = key->hw_key_idx << CAM_CMD_KEY_SHIFT; ctrl = (key->cipher & 0x0f) << 2 | key->keyidx | CAM_WRITE_VALID; + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + ctrl |= BIT(6); for (j = 5; j >= 0; j--) { switch (j) { @@ -4574,7 +4605,7 @@ static int rtl8xxxu_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, { struct rtl8xxxu_priv *priv = hw->priv; - schedule_work(&priv->update_beacon_work); + schedule_delayed_work(&priv->update_beacon_work, 0); return 0; } @@ -4839,10 +4870,9 @@ static void rtl8xxxu_set_basic_rates(struct rtl8xxxu_priv *priv, u32 rate_cfg) dev_dbg(&priv->udev->dev, "%s: rates %08x\n", __func__, rate_cfg); - while (rate_cfg) { - rate_cfg = (rate_cfg >> 1); - rate_idx++; - } + if (rate_cfg) + rate_idx = __fls(rate_cfg); + rtl8xxxu_write8(priv, REG_INIRTS_RATE_SEL, rate_idx); } @@ -4888,14 +4918,20 @@ static void rtl8xxxu_set_aifs(struct rtl8xxxu_priv *priv, u8 slot_time) u8 aifs, aifsn, sifs; int i; - if (priv->vif) { + for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { + if (!priv->vifs[i]) + continue; + struct ieee80211_sta *sta; rcu_read_lock(); - sta = ieee80211_find_sta(priv->vif, priv->vif->bss_conf.bssid); + sta = ieee80211_find_sta(priv->vifs[i], priv->vifs[i]->bss_conf.bssid); if (sta) wireless_mode = rtl8xxxu_wireless_mode(priv->hw, sta); rcu_read_unlock(); + + if (wireless_mode) + break; } if (priv->hw->conf.chandef.chan->band == NL80211_BAND_5GHZ || @@ -4952,6 +4988,7 @@ static void rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u64 changed) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; struct ieee80211_sta *sta; @@ -4964,7 +5001,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_ASSOC) { dev_dbg(dev, "Changed ASSOC: %i!\n", vif->cfg.assoc); - rtl8xxxu_set_linktype(priv, vif->type); + rtl8xxxu_set_linktype(priv, vif->type, rtlvif->port_num); if (vif->cfg.assoc) { u32 ramask; @@ -5004,7 +5041,6 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_update_ra_report(rarpt, highest_rate, sgi, bw); - priv->vif = vif; priv->rssi_level = RTL8XXXU_RATR_STA_INIT; priv->fops->update_rate_mask(priv, ramask, 0, sgi, @@ -5012,7 +5048,8 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, rtl8xxxu_write8(priv, REG_BCN_MAX_ERR, 0xff); - rtl8xxxu_stop_tx_beacon(priv); + if (rtlvif->port_num == 0) + rtl8xxxu_stop_tx_beacon(priv); /* joinbss sequence */ rtl8xxxu_write16(priv, REG_BCN_PSR_RPT, @@ -5054,7 +5091,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changed & BSS_CHANGED_BSSID) { dev_dbg(dev, "Changed BSSID!\n"); - rtl8xxxu_set_bssid(priv, bss_conf->bssid); + rtl8xxxu_set_bssid(priv, bss_conf->bssid, rtlvif->port_num); } if (changed & BSS_CHANGED_BASIC_RATES) { @@ -5070,7 +5107,7 @@ rtl8xxxu_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } if (changed & BSS_CHANGED_BEACON) - schedule_work(&priv->update_beacon_work); + schedule_delayed_work(&priv->update_beacon_work, 0); error: return; @@ -5079,11 +5116,12 @@ error: static int rtl8xxxu_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; dev_dbg(dev, "Start AP mode\n"); - rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid); + rtl8xxxu_set_bssid(priv, vif->bss_conf.bssid, rtlvif->port_num); rtl8xxxu_write16(priv, REG_BCN_INTERVAL, vif->bss_conf.beacon_int); priv->fops->report_connect(priv, RTL8XXXU_BC_MC_MACID, 0, true); @@ -5509,13 +5547,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, struct rtl8xxxu_tx_urb *tx_urb; struct ieee80211_sta *sta = NULL; struct ieee80211_vif *vif = tx_info->control.vif; + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct device *dev = &priv->udev->dev; u32 queue, rts_rate; u16 pktlen = skb->len; int tx_desc_size = priv->fops->tx_desc_size; u8 macid; int ret; - bool ampdu_enable, sgi = false, short_preamble = false; + bool ampdu_enable, sgi = false, short_preamble = false, bmc = false; if (skb_headroom(skb) < tx_desc_size) { dev_warn(dev, @@ -5557,10 +5596,14 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, tx_desc->txdw0 = TXDESC_OWN | TXDESC_FIRST_SEGMENT | TXDESC_LAST_SEGMENT; if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) || - is_broadcast_ether_addr(ieee80211_get_DA(hdr))) + is_broadcast_ether_addr(ieee80211_get_DA(hdr))) { tx_desc->txdw0 |= TXDESC_BROADMULTICAST; + bmc = true; + } + tx_desc->txdw1 = cpu_to_le32(queue << TXDESC_QUEUE_SHIFT); + macid = rtl8xxxu_get_macid(priv, sta); if (tx_info->control.hw_key) { switch (tx_info->control.hw_key->cipher) { @@ -5575,6 +5618,10 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, default: break; } + if (bmc && rtlvif->hw_key_idx != 0xff) { + tx_desc->txdw1 |= cpu_to_le32(TXDESC_EN_DESC_ID); + macid = rtlvif->hw_key_idx; + } } /* (tx_info->flags & IEEE80211_TX_CTL_AMPDU) && */ @@ -5618,7 +5665,6 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw, else rts_rate = 0; - macid = rtl8xxxu_get_macid(priv, sta); priv->fops->fill_txdesc(hw, hdr, tx_info, tx_desc, sgi, short_preamble, ampdu_enable, rts_rate, macid); @@ -5680,18 +5726,44 @@ static void rtl8xxxu_send_beacon_frame(struct ieee80211_hw *hw, static void rtl8xxxu_update_beacon_work_callback(struct work_struct *work) { struct rtl8xxxu_priv *priv = - container_of(work, struct rtl8xxxu_priv, update_beacon_work); + container_of(work, struct rtl8xxxu_priv, update_beacon_work.work); struct ieee80211_hw *hw = priv->hw; - struct ieee80211_vif *vif = priv->vif; + struct ieee80211_vif *vif = priv->vifs[0]; if (!vif) { WARN_ONCE(true, "no vif to update beacon\n"); return; } + if (vif->bss_conf.csa_active) { + if (ieee80211_beacon_cntdwn_is_complete(vif)) { + ieee80211_csa_finish(vif); + return; + } + schedule_delayed_work(&priv->update_beacon_work, + msecs_to_jiffies(vif->bss_conf.beacon_int)); + } rtl8xxxu_send_beacon_frame(hw, vif); } +static inline bool rtl8xxxu_is_packet_match_bssid(struct rtl8xxxu_priv *priv, + struct ieee80211_hdr *hdr, + int port_num) +{ + return priv->vifs[port_num] && + priv->vifs[port_num]->type == NL80211_IFTYPE_STATION && + priv->vifs[port_num]->cfg.assoc && + ether_addr_equal(priv->vifs[port_num]->bss_conf.bssid, hdr->addr2); +} + +static inline bool rtl8xxxu_is_sta_sta(struct rtl8xxxu_priv *priv) +{ + return (priv->vifs[0] && priv->vifs[0]->cfg.assoc && + priv->vifs[0]->type == NL80211_IFTYPE_STATION) && + (priv->vifs[1] && priv->vifs[1]->cfg.assoc && + priv->vifs[1]->type == NL80211_IFTYPE_STATION); +} + void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, struct ieee80211_rx_status *rx_status, struct rtl8723au_phy_stats *phy_stats, @@ -5708,12 +5780,11 @@ void rtl8723au_rx_parse_phystats(struct rtl8xxxu_priv *priv, rx_status->signal = priv->fops->cck_rssi(priv, phy_stats); } else { bool parse_cfo = priv->fops->set_crystal_cap && - priv->vif && - priv->vif->type == NL80211_IFTYPE_STATION && - priv->vif->cfg.assoc && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && - ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2); + !rtl8xxxu_is_sta_sta(priv) && + (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || + rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); if (parse_cfo) { priv->cfo_tracking.cfo_tail[0] = phy_stats->path_cfotail[0]; @@ -5748,12 +5819,11 @@ static void jaguar2_rx_parse_phystats_type1(struct rtl8xxxu_priv *priv, bool crc_icv_err) { bool parse_cfo = priv->fops->set_crystal_cap && - priv->vif && - priv->vif->type == NL80211_IFTYPE_STATION && - priv->vif->cfg.assoc && !crc_icv_err && !ieee80211_is_ctl(hdr->frame_control) && - ether_addr_equal(priv->vif->bss_conf.bssid, hdr->addr2); + !rtl8xxxu_is_sta_sta(priv) && + (rtl8xxxu_is_packet_match_bssid(priv, hdr, 0) || + rtl8xxxu_is_packet_match_bssid(priv, hdr, 1)); u8 pwdb_max = 0; int rx_path; @@ -6029,18 +6099,20 @@ void rtl8723bu_update_bt_link_info(struct rtl8xxxu_priv *priv, u8 bt_info) btcoex->bt_busy = false; } +static inline bool rtl8xxxu_is_assoc(struct rtl8xxxu_priv *priv) +{ + return (priv->vifs[0] && priv->vifs[0]->cfg.assoc) || + (priv->vifs[1] && priv->vifs[1]->cfg.assoc); +} + static void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) { - struct ieee80211_vif *vif; struct rtl8xxxu_btcoex *btcoex; - bool wifi_connected; - vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->cfg.assoc); - if (!wifi_connected) { + if (!rtl8xxxu_is_assoc(priv)) { rtl8723bu_set_ps_tdma(priv, 0x8, 0x0, 0x0, 0x0, 0x0); rtl8723bu_set_coex_with_type(priv, 0); } else if (btcoex->has_sco || btcoex->has_hid || btcoex->has_a2dp) { @@ -6058,15 +6130,11 @@ void rtl8723bu_handle_bt_inquiry(struct rtl8xxxu_priv *priv) static void rtl8723bu_handle_bt_info(struct rtl8xxxu_priv *priv) { - struct ieee80211_vif *vif; struct rtl8xxxu_btcoex *btcoex; - bool wifi_connected; - vif = priv->vif; btcoex = &priv->bt_coex; - wifi_connected = (vif && vif->cfg.assoc); - if (wifi_connected) { + if (rtl8xxxu_is_assoc(priv)) { u32 val32 = 0; u32 high_prio_tx = 0, high_prio_rx = 0; @@ -6563,29 +6631,123 @@ error: return ret; } +static void rtl8xxxu_switch_ports(struct rtl8xxxu_priv *priv) +{ + u8 macid[ETH_ALEN], bssid[ETH_ALEN], macid_1[ETH_ALEN], bssid_1[ETH_ALEN]; + u8 msr, bcn_ctrl, bcn_ctrl_1, atimwnd[2], atimwnd_1[2]; + struct rtl8xxxu_vif *rtlvif; + struct ieee80211_vif *vif; + u8 tsftr[8], tsftr_1[8]; + int i; + + msr = rtl8xxxu_read8(priv, REG_MSR); + bcn_ctrl = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + bcn_ctrl_1 = rtl8xxxu_read8(priv, REG_BEACON_CTRL_1); + + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + atimwnd[i] = rtl8xxxu_read8(priv, REG_ATIMWND + i); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + atimwnd_1[i] = rtl8xxxu_read8(priv, REG_ATIMWND_1 + i); + + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr[i] = rtl8xxxu_read8(priv, REG_TSFTR + i); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + tsftr_1[i] = rtl8xxxu_read8(priv, REG_TSFTR1 + i); + + for (i = 0; i < ARRAY_SIZE(macid); i++) + macid[i] = rtl8xxxu_read8(priv, REG_MACID + i); + + for (i = 0; i < ARRAY_SIZE(bssid); i++) + bssid[i] = rtl8xxxu_read8(priv, REG_BSSID + i); + + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + macid_1[i] = rtl8xxxu_read8(priv, REG_MACID1 + i); + + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + bssid_1[i] = rtl8xxxu_read8(priv, REG_BSSID1 + i); + + /* disable bcn function, disable update TSF */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, (bcn_ctrl & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, (bcn_ctrl_1 & + (~BEACON_FUNCTION_ENABLE)) | BEACON_DISABLE_TSF_UPDATE); + + /* switch msr */ + msr = (msr & 0xf0) | ((msr & 0x03) << 2) | ((msr & 0x0c) >> 2); + rtl8xxxu_write8(priv, REG_MSR, msr); + + /* write port0 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1 & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd_1); i++) + rtl8xxxu_write8(priv, REG_ATIMWND + i, atimwnd_1[i]); + for (i = 0; i < ARRAY_SIZE(tsftr_1); i++) + rtl8xxxu_write8(priv, REG_TSFTR + i, tsftr_1[i]); + for (i = 0; i < ARRAY_SIZE(macid_1); i++) + rtl8xxxu_write8(priv, REG_MACID + i, macid_1[i]); + for (i = 0; i < ARRAY_SIZE(bssid_1); i++) + rtl8xxxu_write8(priv, REG_BSSID + i, bssid_1[i]); + + /* write port1 */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl & ~BEACON_FUNCTION_ENABLE); + for (i = 0; i < ARRAY_SIZE(atimwnd); i++) + rtl8xxxu_write8(priv, REG_ATIMWND_1 + i, atimwnd[i]); + for (i = 0; i < ARRAY_SIZE(tsftr); i++) + rtl8xxxu_write8(priv, REG_TSFTR1 + i, tsftr[i]); + for (i = 0; i < ARRAY_SIZE(macid); i++) + rtl8xxxu_write8(priv, REG_MACID1 + i, macid[i]); + for (i = 0; i < ARRAY_SIZE(bssid); i++) + rtl8xxxu_write8(priv, REG_BSSID1 + i, bssid[i]); + + /* write bcn ctl */ + rtl8xxxu_write8(priv, REG_BEACON_CTRL, bcn_ctrl_1); + rtl8xxxu_write8(priv, REG_BEACON_CTRL_1, bcn_ctrl); + + vif = priv->vifs[0]; + priv->vifs[0] = priv->vifs[1]; + priv->vifs[1] = vif; + + /* priv->vifs[0] is NULL here, based on how this function is currently + * called from rtl8xxxu_add_interface(). + * When this function will be used in the future for a different + * scenario, please check whether vifs[0] or vifs[1] can be NULL and if + * necessary add code to set port_num = 1. + */ + rtlvif = (struct rtl8xxxu_vif *)priv->vifs[1]->drv_priv; + rtlvif->port_num = 1; +} + static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; - int ret; + int port_num; u8 val8; - if (!priv->vif) - priv->vif = vif; + if (!priv->vifs[0]) + port_num = 0; + else if (!priv->vifs[1]) + port_num = 1; else return -EOPNOTSUPP; switch (vif->type) { case NL80211_IFTYPE_STATION: - rtl8xxxu_stop_tx_beacon(priv); + if (port_num == 0) { + rtl8xxxu_stop_tx_beacon(priv); - val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); - val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | - BEACON_DISABLE_TSF_UPDATE; - rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); - ret = 0; + val8 = rtl8xxxu_read8(priv, REG_BEACON_CTRL); + val8 |= BEACON_ATIM | BEACON_FUNCTION_ENABLE | + BEACON_DISABLE_TSF_UPDATE; + rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8); + } break; case NL80211_IFTYPE_AP: + if (port_num == 1) { + rtl8xxxu_switch_ports(priv); + port_num = 0; + } + rtl8xxxu_write8(priv, REG_BEACON_CTRL, BEACON_DISABLE_TSF_UPDATE | BEACON_CTRL_MBSSID); rtl8xxxu_write8(priv, REG_ATIMWND, 0x0c); /* 12ms */ @@ -6602,29 +6764,31 @@ static int rtl8xxxu_add_interface(struct ieee80211_hw *hw, val8 = rtl8xxxu_read8(priv, REG_CCK_CHECK); val8 &= ~BIT_BCN_PORT_SEL; rtl8xxxu_write8(priv, REG_CCK_CHECK, val8); - - ret = 0; break; default: - ret = -EOPNOTSUPP; + return -EOPNOTSUPP; } - rtl8xxxu_set_linktype(priv, vif->type); + priv->vifs[port_num] = vif; + rtlvif->port_num = port_num; + rtlvif->hw_key_idx = 0xff; + + rtl8xxxu_set_linktype(priv, vif->type, port_num); ether_addr_copy(priv->mac_addr, vif->addr); - rtl8xxxu_set_mac(priv); + rtl8xxxu_set_mac(priv, port_num); - return ret; + return 0; } static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; dev_dbg(&priv->udev->dev, "%s\n", __func__); - if (priv->vif) - priv->vif = NULL; + priv->vifs[rtlvif->port_num] = NULL; } static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) @@ -6746,8 +6910,8 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, else rcr |= RCR_CHECK_BSSID_BEACON | RCR_CHECK_BSSID_MATCH; - if (priv->vif && priv->vif->type == NL80211_IFTYPE_AP) - rcr &= ~RCR_CHECK_BSSID_MATCH; + if (priv->vifs[0] && priv->vifs[0]->type == NL80211_IFTYPE_AP) + rcr &= ~(RCR_CHECK_BSSID_MATCH | RCR_CHECK_BSSID_BEACON); if (*total_flags & FIF_CONTROL) rcr |= RCR_ACCEPT_CTRL_FRAME; @@ -6784,11 +6948,19 @@ static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) return 0; } +static int rtl8xxxu_get_free_sec_cam(struct ieee80211_hw *hw) +{ + struct rtl8xxxu_priv *priv = hw->priv; + + return find_first_zero_bit(priv->cam_map, priv->fops->max_sec_cam_num); +} + static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; u8 mac_addr[ETH_ALEN]; @@ -6800,9 +6972,6 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, dev_dbg(dev, "%s: cmd %02x, cipher %08x, index %i\n", __func__, cmd, key->cipher, key->keyidx); - if (vif->type != NL80211_IFTYPE_STATION) - return -EOPNOTSUPP; - if (key->keyidx > 3) return -EOPNOTSUPP; @@ -6826,7 +6995,7 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ether_addr_copy(mac_addr, sta->addr); } else { dev_dbg(dev, "%s: group key\n", __func__); - eth_broadcast_addr(mac_addr); + ether_addr_copy(mac_addr, vif->bss_conf.bssid); } val16 = rtl8xxxu_read16(priv, REG_CR); @@ -6840,16 +7009,28 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, switch (cmd) { case SET_KEY: - key->hw_key_idx = key->keyidx; + + retval = rtl8xxxu_get_free_sec_cam(hw); + if (retval < 0) + return -EOPNOTSUPP; + + key->hw_key_idx = retval; + + if (vif->type == NL80211_IFTYPE_AP && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + rtlvif->hw_key_idx = key->hw_key_idx; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; rtl8xxxu_cam_write(priv, key, mac_addr); + set_bit(key->hw_key_idx, priv->cam_map); retval = 0; break; case DISABLE_KEY: rtl8xxxu_write32(priv, REG_CAM_WRITE, 0x00000000); val32 = CAM_CMD_POLLING | CAM_CMD_WRITE | - key->keyidx << CAM_CMD_KEY_SHIFT; + key->hw_key_idx << CAM_CMD_KEY_SHIFT; rtl8xxxu_write32(priv, REG_CAM_CMD, val32); + rtlvif->hw_key_idx = 0xff; + clear_bit(key->hw_key_idx, priv->cam_map); retval = 0; break; default: @@ -7085,7 +7266,7 @@ static void rtl8xxxu_track_cfo(struct rtl8xxxu_priv *priv) int cfo_khz_a, cfo_khz_b, cfo_average; int crystal_cap; - if (!priv->vif || !priv->vif->cfg.assoc) { + if (!rtl8xxxu_is_assoc(priv)) { /* Reset */ cfo->adjust = true; @@ -7152,11 +7333,15 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) { struct ieee80211_vif *vif; struct rtl8xxxu_priv *priv; + int i; priv = container_of(work, struct rtl8xxxu_priv, ra_watchdog.work); - vif = priv->vif; + for (i = 0; i < ARRAY_SIZE(priv->vifs); i++) { + vif = priv->vifs[i]; + + if (!vif || vif->type != NL80211_IFTYPE_STATION) + continue; - if (vif && vif->type == NL80211_IFTYPE_STATION) { int signal; struct ieee80211_sta *sta; @@ -7167,22 +7352,21 @@ static void rtl8xxxu_watchdog_callback(struct work_struct *work) dev_dbg(dev, "%s: no sta found\n", __func__); rcu_read_unlock(); - goto out; + continue; } rcu_read_unlock(); signal = ieee80211_ave_rssi(vif); - priv->fops->report_rssi(priv, 0, + priv->fops->report_rssi(priv, rtl8xxxu_get_macid(priv, sta), rtl8xxxu_signal_to_snr(signal)); - if (priv->fops->set_crystal_cap) - rtl8xxxu_track_cfo(priv); - rtl8xxxu_refresh_rate_mask(priv, signal, sta, false); } -out: + if (priv->fops->set_crystal_cap) + rtl8xxxu_track_cfo(priv); + schedule_delayed_work(&priv->ra_watchdog, 2 * HZ); } @@ -7304,7 +7488,9 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw) if (priv->usb_interrupts) rtl8xxxu_write32(priv, REG_USB_HIMR, 0); + cancel_work_sync(&priv->c2hcmd_work); cancel_delayed_work_sync(&priv->ra_watchdog); + cancel_delayed_work_sync(&priv->update_beacon_work); rtl8xxxu_free_rx_resources(priv); rtl8xxxu_free_tx_resources(priv); @@ -7315,6 +7501,7 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct rtl8xxxu_sta_info *sta_info = (struct rtl8xxxu_sta_info *)sta->drv_priv; + struct rtl8xxxu_vif *rtlvif = (struct rtl8xxxu_vif *)vif->drv_priv; struct rtl8xxxu_priv *priv = hw->priv; if (vif->type == NL80211_IFTYPE_AP) { @@ -7324,6 +7511,17 @@ static int rtl8xxxu_sta_add(struct ieee80211_hw *hw, rtl8xxxu_refresh_rate_mask(priv, 0, sta, true); priv->fops->report_connect(priv, sta_info->macid, H2C_MACID_ROLE_STA, true); + } else { + switch (rtlvif->port_num) { + case 0: + sta_info->macid = RTL8XXXU_BC_MC_MACID; + break; + case 1: + sta_info->macid = RTL8XXXU_BC_MC_MACID1; + break; + default: + break; + } } return 0; @@ -7476,6 +7674,20 @@ static void rtl8xxxu_deinit_led(struct rtl8xxxu_priv *priv) led_classdev_unregister(led); } +static const struct ieee80211_iface_limit rtl8xxxu_limits[] = { + { .max = 2, .types = BIT(NL80211_IFTYPE_STATION), }, + { .max = 1, .types = BIT(NL80211_IFTYPE_AP), }, +}; + +static const struct ieee80211_iface_combination rtl8xxxu_combinations[] = { + { + .limits = rtl8xxxu_limits, + .n_limits = ARRAY_SIZE(rtl8xxxu_limits), + .max_interfaces = 2, + .num_different_channels = 1, + }, +}; + static int rtl8xxxu_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -7561,7 +7773,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, spin_lock_init(&priv->rx_urb_lock); INIT_WORK(&priv->rx_urb_wq, rtl8xxxu_rx_urb_work); INIT_DELAYED_WORK(&priv->ra_watchdog, rtl8xxxu_watchdog_callback); - INIT_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback); + INIT_DELAYED_WORK(&priv->update_beacon_work, rtl8xxxu_update_beacon_work_callback); skb_queue_head_init(&priv->c2hcmd_queue); usb_set_intfdata(interface, hw); @@ -7611,6 +7823,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, if (ret) goto err_set_intfdata; + hw->vif_data_size = sizeof(struct rtl8xxxu_vif); + hw->wiphy->max_scan_ssids = 1; hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; if (priv->fops->max_macid_num) @@ -7620,6 +7834,13 @@ static int rtl8xxxu_probe(struct usb_interface *interface, hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP); hw->queues = 4; + hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + + if (priv->fops->supports_concurrent) { + hw->wiphy->iface_combinations = rtl8xxxu_combinations; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtl8xxxu_combinations); + } + sband = &rtl8xxxu_supported_band; sband->ht_cap.ht_supported = true; sband->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h index 920ee50e2115..61c0c0ec07b3 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h @@ -146,6 +146,21 @@ #define GPIO_INTM_EDGE_TRIG_IRQ BIT(9) #define REG_LEDCFG0 0x004c +#define LEDCFG0_LED0CM GENMASK(2, 0) +#define LEDCFG0_LED1CM GENMASK(10, 8) +#define LED_MODE_SW_CTRL 0x0 +#define LED_MODE_TX_OR_RX_EVENTS 0x3 +#define LEDCFG0_LED0SV BIT(3) +#define LEDCFG0_LED1SV BIT(11) +#define LED_SW_OFF 0x0 +#define LED_SW_ON 0x1 +#define LEDCFG0_LED0_IO_MODE BIT(7) +#define LEDCFG0_LED1_IO_MODE BIT(15) +#define LED_IO_MODE_OUTPUT 0x0 +#define LED_IO_MODE_INPUT 0x1 +#define LEDCFG0_LED2EN BIT(21) +#define LED_GPIO_DISABLE 0x0 +#define LED_GPIO_ENABLE 0x1 #define LEDCFG0_DPDT_SELECT BIT(23) #define REG_LEDCFG1 0x004d #define LEDCFG1_HW_LED_CONTROL BIT(1) diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.c b/drivers/net/wireless/realtek/rtlwifi/efuse.c index 2e945554ed6d..c1fbc29d5ca1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.c +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.c @@ -1287,18 +1287,44 @@ int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, } EXPORT_SYMBOL_GPL(rtl_get_hwinfo); -void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size) +static void _rtl_fw_block_write_usb(struct ieee80211_hw *hw, u8 *buffer, u32 size) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + u32 start = START_ADDRESS; + u32 n; + + while (size > 0) { + if (size >= 64) + n = 64; + else if (size >= 8) + n = 8; + else + n = 1; + + rtl_write_chunk(rtlpriv, start, n, buffer); + + start += n; + buffer += n; + size -= n; + } +} + +void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size) { struct rtl_priv *rtlpriv = rtl_priv(hw); - u8 *pu4byteptr = (u8 *)buffer; u32 i; - for (i = 0; i < size; i++) - rtl_write_byte(rtlpriv, (START_ADDRESS + i), *(pu4byteptr + i)); + if (rtlpriv->rtlhal.interface == INTF_PCI) { + for (i = 0; i < size; i++) + rtl_write_byte(rtlpriv, (START_ADDRESS + i), + *(buffer + i)); + } else if (rtlpriv->rtlhal.interface == INTF_USB) { + _rtl_fw_block_write_usb(hw, buffer, size); + } } EXPORT_SYMBOL_GPL(rtl_fw_block_write); -void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer, u32 size) { struct rtl_priv *rtlpriv = rtl_priv(hw); diff --git a/drivers/net/wireless/realtek/rtlwifi/efuse.h b/drivers/net/wireless/realtek/rtlwifi/efuse.h index 1ec59f439382..4821625ad1e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/efuse.h +++ b/drivers/net/wireless/realtek/rtlwifi/efuse.h @@ -91,8 +91,8 @@ void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate); int rtl_get_hwinfo(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv, int max_size, u8 *hwinfo, int *params); void rtl_fill_dummy(u8 *pfwbuf, u32 *pfwlen); -void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, const u8 *buffer, +void rtl_fw_page_write(struct ieee80211_hw *hw, u32 page, u8 *buffer, u32 size); -void rtl_fw_block_write(struct ieee80211_hw *hw, const u8 *buffer, u32 size); +void rtl_fw_block_write(struct ieee80211_hw *hw, u8 *buffer, u32 size); void rtl_efuse_ops_init(struct ieee80211_hw *hw); #endif diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 96ce05bcf0b3..d059cfe5a2a9 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -378,13 +378,13 @@ static void _rtl_pci_io_handler_init(struct device *dev, rtlpriv->io.dev = dev; - rtlpriv->io.write8_async = pci_write8_async; - rtlpriv->io.write16_async = pci_write16_async; - rtlpriv->io.write32_async = pci_write32_async; + rtlpriv->io.write8 = pci_write8_async; + rtlpriv->io.write16 = pci_write16_async; + rtlpriv->io.write32 = pci_write32_async; - rtlpriv->io.read8_sync = pci_read8_sync; - rtlpriv->io.read16_sync = pci_read16_sync; - rtlpriv->io.read32_sync = pci_read32_sync; + rtlpriv->io.read8 = pci_read8_sync; + rtlpriv->io.read16 = pci_read16_sync; + rtlpriv->io.read32 = pci_read32_sync; } static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c index 50e139186a93..ed151754fc6e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/trx.c @@ -350,7 +350,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool defaultadapter = true; __le32 *pdesc = (__le32 *)pdesc8; u16 seq_number; __le16 fc = hdr->frame_control; @@ -503,9 +502,6 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) { set_tx_desc_hwseq_en(pdesc, 1); set_tx_desc_pkt_id(pdesc, 8); - - if (!defaultadapter) - set_tx_desc_qos(pdesc, 1); } set_tx_desc_more_frag(pdesc, (lastseg ? 0 : 1)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index 20b4aac69642..9f4cf09090d6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -40,7 +40,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.thermalvalue = 0; /* for firmware buf */ - rtlpriv->rtlhal.pfirmware = vzalloc(0x4000); + rtlpriv->rtlhal.pfirmware = kmalloc(0x4000, GFP_KERNEL); if (!rtlpriv->rtlhal.pfirmware) { pr_err("Can't alloc buffer for fw\n"); return 1; @@ -61,7 +61,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) fw_name, rtlpriv->io.dev, GFP_KERNEL, hw, rtl_fw_cb); if (err) { - vfree(rtlpriv->rtlhal.pfirmware); + kfree(rtlpriv->rtlhal.pfirmware); rtlpriv->rtlhal.pfirmware = NULL; } return err; @@ -72,7 +72,7 @@ static void rtl92cu_deinit_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); if (rtlpriv->rtlhal.pfirmware) { - vfree(rtlpriv->rtlhal.pfirmware); + kfree(rtlpriv->rtlhal.pfirmware); rtlpriv->rtlhal.pfirmware = NULL; } } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index 2f44c8aa6066..e5c81c1c63c0 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -475,7 +475,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool defaultadapter = true; u8 *qc = ieee80211_get_qos_ctl(hdr); u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; u16 seq_number; @@ -587,8 +586,6 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, ppsc->fwctrl_lps) { set_tx_desc_hwseq_en(txdesc, 1); set_tx_desc_pkt_id(txdesc, 8); - if (!defaultadapter) - set_tx_desc_qos(txdesc, 1); } if (ieee80211_has_morefrags(fc)) set_tx_desc_more_frag(txdesc, 1); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c index 02ac69c08ed3..192982ec8152 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/trx.c @@ -42,6 +42,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, bool packet_beacon) { struct rtl_priv *rtlpriv = rtl_priv(hw); + struct rtl_phy *rtlphy = &(rtlpriv->phy); struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv); struct phy_sts_cck_8192d *cck_buf; s8 rx_pwr_all, rx_pwr[4]; @@ -62,9 +63,7 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192d *)p_drvinfo; if (ppsc->rfpwr_state == ERFON) - cck_highpwr = (u8) rtl_get_bbreg(hw, - RFPGA0_XA_HSSIPARAMETER2, - BIT(9)); + cck_highpwr = rtlphy->cck_high_power; else cck_highpwr = false; if (!cck_highpwr) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c index d9823ddab7be..65bfc14702f4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/trx.c @@ -349,7 +349,6 @@ void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw, struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - bool b_defaultadapter = true; /* bool b_trigger_ac = false; */ u8 *pdesc8 = (u8 *)pdesc_tx; __le32 *pdesc = (__le32 *)pdesc8; @@ -503,10 +502,7 @@ void rtl8723e_tx_fill_desc(struct ieee80211_hw *hw, set_tx_desc_hwseq_en_8723(pdesc, 1); /* set_tx_desc_hwseq_en(pdesc, 1); */ /* set_tx_desc_pkt_id(pdesc, 8); */ - - if (!b_defaultadapter) - set_tx_desc_hwseq_sel_8723(pdesc, 1); - /* set_tx_desc_qos(pdesc, 1); */ + /* set_tx_desc_qos(pdesc, 1); */ } set_tx_desc_more_frag(pdesc, (lastseg ? 0 : 1)); diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 30bf2775a335..1fc480fe18ad 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -23,86 +23,23 @@ MODULE_DESCRIPTION("USB basic driver for rtlwifi"); #define MAX_USBCTRL_VENDORREQ_TIMES 10 -static void usbctrl_async_callback(struct urb *urb) -{ - if (urb) { - /* free dr */ - kfree(urb->setup_packet); - /* free databuf */ - kfree(urb->transfer_buffer); - } -} - -static int _usbctrl_vendorreq_async_write(struct usb_device *udev, u8 request, - u16 value, u16 index, void *pdata, - u16 len) -{ - int rc; - unsigned int pipe; - u8 reqtype; - struct usb_ctrlrequest *dr; - struct urb *urb; - const u16 databuf_maxlen = REALTEK_USB_VENQT_MAX_BUF_SIZE; - u8 *databuf; - - if (WARN_ON_ONCE(len > databuf_maxlen)) - len = databuf_maxlen; - - pipe = usb_sndctrlpipe(udev, 0); /* write_out */ - reqtype = REALTEK_USB_VENQT_WRITE; - - dr = kzalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) - return -ENOMEM; - - databuf = kzalloc(databuf_maxlen, GFP_ATOMIC); - if (!databuf) { - kfree(dr); - return -ENOMEM; - } - - urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!urb) { - kfree(databuf); - kfree(dr); - return -ENOMEM; - } - - dr->bRequestType = reqtype; - dr->bRequest = request; - dr->wValue = cpu_to_le16(value); - dr->wIndex = cpu_to_le16(index); - dr->wLength = cpu_to_le16(len); - /* data are already in little-endian order */ - memcpy(databuf, pdata, len); - usb_fill_control_urb(urb, udev, pipe, - (unsigned char *)dr, databuf, len, - usbctrl_async_callback, NULL); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc < 0) { - kfree(databuf); - kfree(dr); - } - usb_free_urb(urb); - return rc; -} - -static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, - u16 value, u16 index, void *pdata, - u16 len) +static void _usbctrl_vendorreq_sync(struct usb_device *udev, u8 reqtype, + u16 value, void *pdata, u16 len) { unsigned int pipe; int status; - u8 reqtype; int vendorreq_times = 0; static int count; - pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ - reqtype = REALTEK_USB_VENQT_READ; + if (reqtype == REALTEK_USB_VENQT_READ) + pipe = usb_rcvctrlpipe(udev, 0); /* read_in */ + else + pipe = usb_sndctrlpipe(udev, 0); /* write_out */ do { - status = usb_control_msg(udev, pipe, request, reqtype, value, - index, pdata, len, 1000); + status = usb_control_msg(udev, pipe, REALTEK_USB_VENQT_CMD_REQ, + reqtype, value, REALTEK_USB_VENQT_CMD_IDX, + pdata, len, 1000); if (status < 0) { /* firmware download is checksumed, don't retry */ if ((value >= FW_8192C_START_ADDRESS && @@ -114,18 +51,15 @@ static int _usbctrl_vendorreq_sync_read(struct usb_device *udev, u8 request, } while (++vendorreq_times < MAX_USBCTRL_VENDORREQ_TIMES); if (status < 0 && count++ < 4) - pr_err("reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x\n", - value, status, *(u32 *)pdata); - return status; + dev_err(&udev->dev, "reg 0x%x, usbctrl_vendorreq TimeOut! status:0x%x value=0x%x reqtype=0x%x\n", + value, status, *(u32 *)pdata, reqtype); } static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) { struct device *dev = rtlpriv->io.dev; struct usb_device *udev = to_usb_device(dev); - u8 request; u16 wvalue; - u16 index; __le32 *data; unsigned long flags; @@ -134,14 +68,33 @@ static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) rtlpriv->usb_data_index = 0; data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)addr; - _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_READ, wvalue, data, len); return le32_to_cpu(*data); } + +static void _usb_write_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val, u16 len) +{ + struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(dev); + unsigned long flags; + __le32 *data; + u16 wvalue; + + spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); + + wvalue = (u16)(addr & 0x0000ffff); + *data = cpu_to_le32(val); + + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_WRITE, wvalue, data, len); +} + static u8 _usb_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { return (u8)_usb_read_sync(rtlpriv, addr, 1); @@ -157,45 +110,27 @@ static u32 _usb_read32_sync(struct rtl_priv *rtlpriv, u32 addr) return _usb_read_sync(rtlpriv, addr, 4); } -static void _usb_write_async(struct usb_device *udev, u32 addr, u32 val, - u16 len) +static void _usb_write8_sync(struct rtl_priv *rtlpriv, u32 addr, u8 val) { - u8 request; - u16 wvalue; - u16 index; - __le32 data; - int ret; - - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ - wvalue = (u16)(addr&0x0000ffff); - data = cpu_to_le32(val); - - ret = _usbctrl_vendorreq_async_write(udev, request, wvalue, - index, &data, len); - if (ret < 0) - dev_err(&udev->dev, "error %d writing at 0x%x\n", ret, addr); + _usb_write_sync(rtlpriv, addr, val, 1); } -static void _usb_write8_async(struct rtl_priv *rtlpriv, u32 addr, u8 val) +static void _usb_write16_sync(struct rtl_priv *rtlpriv, u32 addr, u16 val) { - struct device *dev = rtlpriv->io.dev; - - _usb_write_async(to_usb_device(dev), addr, val, 1); + _usb_write_sync(rtlpriv, addr, val, 2); } -static void _usb_write16_async(struct rtl_priv *rtlpriv, u32 addr, u16 val) +static void _usb_write32_sync(struct rtl_priv *rtlpriv, u32 addr, u32 val) { - struct device *dev = rtlpriv->io.dev; - - _usb_write_async(to_usb_device(dev), addr, val, 2); + _usb_write_sync(rtlpriv, addr, val, 4); } -static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) +static void _usb_write_chunk_sync(struct rtl_priv *rtlpriv, u32 addr, + u32 length, u8 *data) { - struct device *dev = rtlpriv->io.dev; + struct usb_device *udev = to_usb_device(rtlpriv->io.dev); - _usb_write_async(to_usb_device(dev), addr, val, 4); + _usbctrl_vendorreq_sync(udev, REALTEK_USB_VENQT_WRITE, addr, data, length); } static void _rtl_usb_io_handler_init(struct device *dev, @@ -205,12 +140,13 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.dev = dev; mutex_init(&rtlpriv->io.bb_mutex); - rtlpriv->io.write8_async = _usb_write8_async; - rtlpriv->io.write16_async = _usb_write16_async; - rtlpriv->io.write32_async = _usb_write32_async; - rtlpriv->io.read8_sync = _usb_read8_sync; - rtlpriv->io.read16_sync = _usb_read16_sync; - rtlpriv->io.read32_sync = _usb_read32_sync; + rtlpriv->io.write8 = _usb_write8_sync; + rtlpriv->io.write16 = _usb_write16_sync; + rtlpriv->io.write32 = _usb_write32_sync; + rtlpriv->io.write_chunk = _usb_write_chunk_sync; + rtlpriv->io.read8 = _usb_read8_sync; + rtlpriv->io.read16 = _usb_read16_sync; + rtlpriv->io.read32 = _usb_read32_sync; } static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index d87cd2252eac..3821f6e31447 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -1447,13 +1447,15 @@ struct rtl_io { /*PCI IO map */ unsigned long pci_base_addr; /*device I/O address */ - void (*write8_async)(struct rtl_priv *rtlpriv, u32 addr, u8 val); - void (*write16_async)(struct rtl_priv *rtlpriv, u32 addr, u16 val); - void (*write32_async)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + void (*write8)(struct rtl_priv *rtlpriv, u32 addr, u8 val); + void (*write16)(struct rtl_priv *rtlpriv, u32 addr, u16 val); + void (*write32)(struct rtl_priv *rtlpriv, u32 addr, u32 val); + void (*write_chunk)(struct rtl_priv *rtlpriv, u32 addr, u32 length, + u8 *data); - u8 (*read8_sync)(struct rtl_priv *rtlpriv, u32 addr); - u16 (*read16_sync)(struct rtl_priv *rtlpriv, u32 addr); - u32 (*read32_sync)(struct rtl_priv *rtlpriv, u32 addr); + u8 (*read8)(struct rtl_priv *rtlpriv, u32 addr); + u16 (*read16)(struct rtl_priv *rtlpriv, u32 addr); + u32 (*read32)(struct rtl_priv *rtlpriv, u32 addr); }; @@ -2916,25 +2918,25 @@ extern u8 channel5g_80m[CHANNEL_MAX_NUMBER_5G_80M]; static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read8_sync(rtlpriv, addr); + return rtlpriv->io.read8(rtlpriv, addr); } static inline u16 rtl_read_word(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read16_sync(rtlpriv, addr); + return rtlpriv->io.read16(rtlpriv, addr); } static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr) { - return rtlpriv->io.read32_sync(rtlpriv, addr); + return rtlpriv->io.read32(rtlpriv, addr); } static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8) { - rtlpriv->io.write8_async(rtlpriv, addr, val8); + rtlpriv->io.write8(rtlpriv, addr, val8); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read8_sync(rtlpriv, addr); + rtlpriv->io.read8(rtlpriv, addr); } static inline void rtl_write_byte_with_val32(struct ieee80211_hw *hw, @@ -2947,19 +2949,25 @@ static inline void rtl_write_byte_with_val32(struct ieee80211_hw *hw, static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16) { - rtlpriv->io.write16_async(rtlpriv, addr, val16); + rtlpriv->io.write16(rtlpriv, addr, val16); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read16_sync(rtlpriv, addr); + rtlpriv->io.read16(rtlpriv, addr); } static inline void rtl_write_dword(struct rtl_priv *rtlpriv, u32 addr, u32 val32) { - rtlpriv->io.write32_async(rtlpriv, addr, val32); + rtlpriv->io.write32(rtlpriv, addr, val32); if (rtlpriv->cfg->write_readback) - rtlpriv->io.read32_sync(rtlpriv, addr); + rtlpriv->io.read32(rtlpriv, addr); +} + +static inline void rtl_write_chunk(struct rtl_priv *rtlpriv, + u32 addr, u32 length, u8 *data) +{ + rtlpriv->io.write_chunk(rtlpriv, addr, length, data); } static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/realtek/rtw88/debug.c b/drivers/net/wireless/realtek/rtw88/debug.c index 1b2ad81838be..5b2036798159 100644 --- a/drivers/net/wireless/realtek/rtw88/debug.c +++ b/drivers/net/wireless/realtek/rtw88/debug.c @@ -316,23 +316,13 @@ static ssize_t rtw_debugfs_set_single_input(struct file *filp, { struct seq_file *seqpriv = (struct seq_file *)filp->private_data; struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; - struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - char tmp[32 + 1]; u32 input; - int num; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtou32_from_user(buffer, count, 0, &input); if (ret) return ret; - num = kstrtoint(tmp, 0, &input); - - if (num) { - rtw_warn(rtwdev, "kstrtoint failed\n"); - return num; - } - debugfs_priv->cb_data = input; return count; @@ -485,19 +475,12 @@ static ssize_t rtw_debugfs_set_fix_rate(struct file *filp, struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dm_info *dm_info = &rtwdev->dm_info; u8 fix_rate; - char tmp[32 + 1]; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtou8_from_user(buffer, count, 0, &fix_rate); if (ret) return ret; - ret = kstrtou8(tmp, 0, &fix_rate); - if (ret) { - rtw_warn(rtwdev, "invalid args, [rate]\n"); - return ret; - } - dm_info->fix_rate = fix_rate; return count; @@ -879,20 +862,13 @@ static ssize_t rtw_debugfs_set_coex_enable(struct file *filp, struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_coex *coex = &rtwdev->coex; - char tmp[32 + 1]; bool enable; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtobool_from_user(buffer, count, &enable); if (ret) return ret; - ret = kstrtobool(tmp, &enable); - if (ret) { - rtw_warn(rtwdev, "invalid arguments\n"); - return ret; - } - mutex_lock(&rtwdev->mutex); coex->manual_control = !enable; mutex_unlock(&rtwdev->mutex); @@ -951,18 +927,13 @@ static ssize_t rtw_debugfs_set_fw_crash(struct file *filp, struct seq_file *seqpriv = (struct seq_file *)filp->private_data; struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; - char tmp[32 + 1]; bool input; int ret; - ret = rtw_debugfs_copy_from_user(tmp, sizeof(tmp), buffer, count, 1); + ret = kstrtobool_from_user(buffer, count, &input); if (ret) return ret; - ret = kstrtobool(tmp, &input); - if (ret) - return -EINVAL; - if (!input) return -EINVAL; @@ -1030,11 +1001,12 @@ static ssize_t rtw_debugfs_set_dm_cap(struct file *filp, struct rtw_debugfs_priv *debugfs_priv = seqpriv->private; struct rtw_dev *rtwdev = debugfs_priv->rtwdev; struct rtw_dm_info *dm_info = &rtwdev->dm_info; - int bit; + int ret, bit; bool en; - if (kstrtoint_from_user(buffer, count, 10, &bit)) - return -EINVAL; + ret = kstrtoint_from_user(buffer, count, 10, &bit); + if (ret) + return ret; en = bit > 0; bit = abs(bit); diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 2bfc0e822b8d..9986a4cb37eb 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -1450,6 +1450,7 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) { struct rtw_pci *rtwpci = (struct rtw_pci *)rtwdev->priv; const struct rtw_chip_info *chip = rtwdev->chip; + struct rtw_efuse *efuse = &rtwdev->efuse; struct pci_dev *pdev = rtwpci->pdev; const struct rtw_intf_phy_para *para; u16 cut; @@ -1498,6 +1499,9 @@ static void rtw_pci_phy_cfg(struct rtw_dev *rtwdev) rtw_err(rtwdev, "failed to set PCI cap, ret = %d\n", ret); } + + if (chip->id == RTW_CHIP_TYPE_8822C && efuse->rfe_option == 5) + rtw_write32_mask(rtwdev, REG_ANAPARSW_MAC_0, BIT_CF_L_V2, 0x1); } static int __maybe_unused rtw_pci_suspend(struct device *dev) diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h index 1634f03784f1..b122f226924b 100644 --- a/drivers/net/wireless/realtek/rtw88/reg.h +++ b/drivers/net/wireless/realtek/rtw88/reg.h @@ -557,6 +557,9 @@ #define REG_RFE_INV16 0x0cbe #define BIT_RFE_BUF_EN BIT(3) +#define REG_ANAPARSW_MAC_0 0x1010 +#define BIT_CF_L_V2 GENMASK(29, 28) + #define REG_ANAPAR_XTAL_0 0x1040 #define BIT_XCAP_0 GENMASK(23, 10) #define REG_CPU_DMEM_CON 0x1080 diff --git a/drivers/net/wireless/realtek/rtw89/cam.c b/drivers/net/wireless/realtek/rtw89/cam.c index 914c94988b2f..11fbdd142162 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.c +++ b/drivers/net/wireless/realtek/rtw89/cam.c @@ -777,3 +777,64 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, SET_DCTL_SEC_ENT5_V1(cmd, addr_cam->sec_ent[5]); SET_DCTL_SEC_ENT6_V1(cmd, addr_cam->sec_ent[6]); } + +void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, + struct rtw89_h2c_dctlinfo_ud_v2 *h2c) +{ + struct rtw89_addr_cam_entry *addr_cam = rtw89_get_addr_cam_of(rtwvif, rtwsta); + + h2c->c0 = le32_encode_bits(rtwsta ? rtwsta->mac_id : rtwvif->mac_id, + DCTLINFO_V2_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V2_C0_OP); + + h2c->w4 = le32_encode_bits(addr_cam->sec_ent_keyid[0], + DCTLINFO_V2_W4_SEC_ENT0_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[1], + DCTLINFO_V2_W4_SEC_ENT1_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[2], + DCTLINFO_V2_W4_SEC_ENT2_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[3], + DCTLINFO_V2_W4_SEC_ENT3_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[4], + DCTLINFO_V2_W4_SEC_ENT4_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[5], + DCTLINFO_V2_W4_SEC_ENT5_KEYID) | + le32_encode_bits(addr_cam->sec_ent_keyid[6], + DCTLINFO_V2_W4_SEC_ENT6_KEYID); + h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_SEC_ENT0_KEYID | + DCTLINFO_V2_W4_SEC_ENT1_KEYID | + DCTLINFO_V2_W4_SEC_ENT2_KEYID | + DCTLINFO_V2_W4_SEC_ENT3_KEYID | + DCTLINFO_V2_W4_SEC_ENT4_KEYID | + DCTLINFO_V2_W4_SEC_ENT5_KEYID | + DCTLINFO_V2_W4_SEC_ENT6_KEYID); + + h2c->w5 = le32_encode_bits(addr_cam->sec_cam_map[0], + DCTLINFO_V2_W5_SEC_ENT_VALID_V1) | + le32_encode_bits(addr_cam->sec_ent[0], + DCTLINFO_V2_W5_SEC_ENT0_V1); + h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_SEC_ENT_VALID_V1 | + DCTLINFO_V2_W5_SEC_ENT0_V1); + + h2c->w6 = le32_encode_bits(addr_cam->sec_ent[1], + DCTLINFO_V2_W6_SEC_ENT1_V1) | + le32_encode_bits(addr_cam->sec_ent[2], + DCTLINFO_V2_W6_SEC_ENT2_V1) | + le32_encode_bits(addr_cam->sec_ent[3], + DCTLINFO_V2_W6_SEC_ENT3_V1) | + le32_encode_bits(addr_cam->sec_ent[4], + DCTLINFO_V2_W6_SEC_ENT4_V1); + h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_SEC_ENT1_V1 | + DCTLINFO_V2_W6_SEC_ENT2_V1 | + DCTLINFO_V2_W6_SEC_ENT3_V1 | + DCTLINFO_V2_W6_SEC_ENT4_V1); + + h2c->w7 = le32_encode_bits(addr_cam->sec_ent[5], + DCTLINFO_V2_W7_SEC_ENT5_V1) | + le32_encode_bits(addr_cam->sec_ent[6], + DCTLINFO_V2_W7_SEC_ENT6_V1); + h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_SEC_ENT5_V1 | + DCTLINFO_V2_W7_SEC_ENT6_V1); +} diff --git a/drivers/net/wireless/realtek/rtw89/cam.h b/drivers/net/wireless/realtek/rtw89/cam.h index 83c160a614e6..fa09d11c345c 100644 --- a/drivers/net/wireless/realtek/rtw89/cam.h +++ b/drivers/net/wireless/realtek/rtw89/cam.h @@ -352,6 +352,111 @@ static inline void FWCMD_SET_ADDR_BSSID_BSSID5(void *cmd, u32 value) le32p_replace_bits((__le32 *)(cmd) + 14, value, GENMASK(31, 24)); } +struct rtw89_h2c_dctlinfo_ud_v2 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define DCTLINFO_V2_C0_MACID GENMASK(6, 0) +#define DCTLINFO_V2_C0_OP BIT(7) + +#define DCTLINFO_V2_W0_QOS_FIELD_H GENMASK(7, 0) +#define DCTLINFO_V2_W0_HW_EXSEQ_MACID GENMASK(14, 8) +#define DCTLINFO_V2_W0_QOS_DATA BIT(15) +#define DCTLINFO_V2_W0_AES_IV_L GENMASK(31, 16) +#define DCTLINFO_V2_W0_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W1_AES_IV_H GENMASK(31, 0) +#define DCTLINFO_V2_W1_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W2_SEQ0 GENMASK(11, 0) +#define DCTLINFO_V2_W2_SEQ1 GENMASK(23, 12) +#define DCTLINFO_V2_W2_AMSDU_MAX_LEN GENMASK(26, 24) +#define DCTLINFO_V2_W2_STA_AMSDU_EN BIT(27) +#define DCTLINFO_V2_W2_CHKSUM_OFLD_EN BIT(28) +#define DCTLINFO_V2_W2_WITH_LLC BIT(29) +#define DCTLINFO_V2_W2_NAT25_EN BIT(30) +#define DCTLINFO_V2_W2_IS_MLD BIT(31) +#define DCTLINFO_V2_W2_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W3_SEQ2 GENMASK(11, 0) +#define DCTLINFO_V2_W3_SEQ3 GENMASK(23, 12) +#define DCTLINFO_V2_W3_TGT_IND GENMASK(27, 24) +#define DCTLINFO_V2_W3_TGT_IND_EN BIT(28) +#define DCTLINFO_V2_W3_HTC_LB GENMASK(31, 29) +#define DCTLINFO_V2_W3_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W4_VLAN_TAG_SEL GENMASK(7, 5) +#define DCTLINFO_V2_W4_HTC_ORDER BIT(8) +#define DCTLINFO_V2_W4_SEC_KEY_ID GENMASK(10, 9) +#define DCTLINFO_V2_W4_VLAN_RX_DYNAMIC_PCP_EN BIT(11) +#define DCTLINFO_V2_W4_VLAN_RX_PKT_DROP BIT(12) +#define DCTLINFO_V2_W4_VLAN_RX_VALID BIT(13) +#define DCTLINFO_V2_W4_VLAN_TX_VALID BIT(14) +#define DCTLINFO_V2_W4_WAPI BIT(15) +#define DCTLINFO_V2_W4_SEC_ENT_MODE GENMASK(17, 16) +#define DCTLINFO_V2_W4_SEC_ENT0_KEYID GENMASK(19, 18) +#define DCTLINFO_V2_W4_SEC_ENT1_KEYID GENMASK(21, 20) +#define DCTLINFO_V2_W4_SEC_ENT2_KEYID GENMASK(23, 22) +#define DCTLINFO_V2_W4_SEC_ENT3_KEYID GENMASK(25, 24) +#define DCTLINFO_V2_W4_SEC_ENT4_KEYID GENMASK(27, 26) +#define DCTLINFO_V2_W4_SEC_ENT5_KEYID GENMASK(29, 28) +#define DCTLINFO_V2_W4_SEC_ENT6_KEYID GENMASK(31, 30) +#define DCTLINFO_V2_W4_ALL GENMASK(31, 5) +#define DCTLINFO_V2_W5_SEC_ENT7_KEYID GENMASK(1, 0) +#define DCTLINFO_V2_W5_SEC_ENT8_KEYID GENMASK(3, 2) +#define DCTLINFO_V2_W5_SEC_ENT_VALID_V1 GENMASK(23, 8) +#define DCTLINFO_V2_W5_SEC_ENT0_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W5_ALL (GENMASK(31, 8) | GENMASK(3, 0)) +#define DCTLINFO_V2_W6_SEC_ENT1_V1 GENMASK(7, 0) +#define DCTLINFO_V2_W6_SEC_ENT2_V1 GENMASK(15, 8) +#define DCTLINFO_V2_W6_SEC_ENT3_V1 GENMASK(23, 16) +#define DCTLINFO_V2_W6_SEC_ENT4_V1 GENMASK(31, 24) +#define DCTLINFO_V2_W6_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W7_SEC_ENT5_V1 GENMASK(7, 0) +#define DCTLINFO_V2_W7_SEC_ENT6_V1 GENMASK(15, 8) +#define DCTLINFO_V2_W7_SEC_ENT7 GENMASK(23, 16) +#define DCTLINFO_V2_W7_SEC_ENT8 GENMASK(31, 24) +#define DCTLINFO_V2_W7_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W8_MLD_SMA_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W8_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W9_MLD_SMA_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W9_MLD_TMA_L_V1 GENMASK(31, 16) +#define DCTLINFO_V2_W9_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W10_MLD_TMA_H_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W10_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W11_MLD_TA_BSSID_L_V1 GENMASK(31, 0) +#define DCTLINFO_V2_W11_ALL GENMASK(31, 0) +#define DCTLINFO_V2_W12_MLD_TA_BSSID_H_V1 GENMASK(15, 0) +#define DCTLINFO_V2_W12_ALL GENMASK(15, 0) + int rtw89_cam_init(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); void rtw89_cam_deinit(struct rtw89_dev *rtwdev, struct rtw89_vif *vif); int rtw89_cam_init_addr_cam(struct rtw89_dev *rtwdev, @@ -373,6 +478,10 @@ void rtw89_cam_fill_dctl_sec_cam_info_v1(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, u8 *cmd); +void rtw89_cam_fill_dctl_sec_cam_info_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta, + struct rtw89_h2c_dctlinfo_ud_v2 *h2c); int rtw89_cam_fill_bssid_cam_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, u8 *cmd); diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index cbf6821af6b8..21449cb9b069 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -1494,7 +1494,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) if (!rtwvif_go->chanctx_assigned) return; - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif_go); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_go); } static void rtw89_mcc_start_beacon_noa(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index fd527a249996..260da86bf04a 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -1176,7 +1176,8 @@ static __le32 rtw89_build_txwd_info2_v1(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info4(struct rtw89_tx_desc_info *desc_info) { - u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, 1) | + bool rts_en = !desc_info->is_bmc; + u32 dword = FIELD_PREP(RTW89_TXWD_INFO4_RTS_EN, rts_en) | FIELD_PREP(RTW89_TXWD_INFO4_HW_RTS_EN, 1); return cpu_to_le32(dword); @@ -1329,7 +1330,8 @@ static __le32 rtw89_build_txwd_info2_v2(struct rtw89_tx_desc_info *desc_info) static __le32 rtw89_build_txwd_info4_v2(struct rtw89_tx_desc_info *desc_info) { - u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, 1) | + bool rts_en = !desc_info->is_bmc; + u32 dword = FIELD_PREP(BE_TXD_INFO4_RTS_EN, rts_en) | FIELD_PREP(BE_TXD_INFO4_HW_RTS_EN, 1); return cpu_to_le32(dword); @@ -3345,6 +3347,14 @@ int rtw89_core_sta_add(struct rtw89_dev *rtwdev, return ret; } + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); + if (ret) + return ret; + + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + if (ret) + return ret; + rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_REMOTE_STA_CHANGE); } @@ -3393,7 +3403,7 @@ int rtw89_core_sta_disconnect(struct rtw89_dev *rtwdev, rtw89_fw_release_general_pkt_list_vif(rtwdev, rtwvif, true); } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; @@ -3442,7 +3452,7 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, } } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c cmac table\n"); return ret; @@ -3485,6 +3495,8 @@ int rtw89_core_sta_assoc(struct rtw89_dev *rtwdev, rtw89_warn(rtwdev, "failed to send h2c general packet\n"); return ret; } + + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true); } return ret; @@ -3611,7 +3623,8 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, cpu_to_le16(867), cpu_to_le16(1733), cpu_to_le16(2600), cpu_to_le16(3467), }; const struct rtw89_chip_info *chip = rtwdev->chip; - const __le16 *highest = chip->support_bw160 ? highest_bw160 : highest_bw80; + const __le16 *highest = chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160) ? + highest_bw160 : highest_bw80; struct rtw89_hal *hal = &rtwdev->hal; u16 tx_mcs_map = 0, rx_mcs_map = 0; u8 sts_cap = 3; @@ -3640,34 +3653,34 @@ static void rtw89_init_vht_cap(struct rtw89_dev *rtwdev, vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; vht_cap->cap |= sts_cap << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT; - if (chip->support_bw160) + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) vht_cap->cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | IEEE80211_VHT_CAP_SHORT_GI_160; vht_cap->vht_mcs.rx_mcs_map = cpu_to_le16(rx_mcs_map); vht_cap->vht_mcs.tx_mcs_map = cpu_to_le16(tx_mcs_map); vht_cap->vht_mcs.rx_highest = highest[hal->rx_nss - 1]; vht_cap->vht_mcs.tx_highest = highest[hal->tx_nss - 1]; -} -#define RTW89_SBAND_IFTYPES_NR 2 + if (ieee80211_hw_check(rtwdev->hw, SUPPORTS_VHT_EXT_NSS_BW)) + vht_cap->vht_mcs.tx_highest |= + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); +} static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, enum nl80211_band band, - struct ieee80211_supported_band *sband) + enum nl80211_iftype iftype, + struct ieee80211_sband_iftype_data *iftype_data) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_hal *hal = &rtwdev->hal; - struct ieee80211_sband_iftype_data *iftype_data; bool no_ng16 = (chip->chip_id == RTL8852A && hal->cv == CHIP_CBV) || (chip->chip_id == RTL8852B && hal->cv == CHIP_CAV); + struct ieee80211_sta_he_cap *he_cap; + int nss = hal->rx_nss; + u8 *mac_cap_info; + u8 *phy_cap_info; u16 mcs_map = 0; int i; - int nss = hal->rx_nss; - int idx = 0; - - iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL); - if (!iftype_data) - return; for (i = 0; i < 8; i++) { if (i < nss) @@ -3676,12 +3689,198 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, mcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); } - for (i = 0; i < NUM_NL80211_IFTYPES; i++) { - struct ieee80211_sta_he_cap *he_cap; - u8 *mac_cap_info; - u8 *phy_cap_info; + he_cap = &iftype_data->he_cap; + mac_cap_info = he_cap->he_cap_elem.mac_cap_info; + phy_cap_info = he_cap->he_cap_elem.phy_cap_info; + + he_cap->has_he = true; + mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; + if (iftype == NL80211_IFTYPE_STATION) + mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; + mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK | + IEEE80211_HE_MAC_CAP2_BSR; + mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2; + if (iftype == NL80211_IFTYPE_AP) + mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL; + mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS | + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; + if (iftype == NL80211_IFTYPE_STATION) + mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; + if (band == NL80211_BAND_2GHZ) { + phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + } else { + phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) + phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + } + phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | + IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; + phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | + IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | + IEEE80211_HE_PHY_CAP2_DOPPLER_TX; + phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM; + if (iftype == NL80211_IFTYPE_STATION) + phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM | + IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; + if (iftype == NL80211_IFTYPE_AP) + phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; + phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) + phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; + phy_cap_info[5] = no_ng16 ? 0 : + IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | + IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; + phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | + IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; + phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP7_MAX_NC_1; + phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) + phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, + IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); + if (iftype == NL80211_IFTYPE_STATION) + phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; + he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map); + he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map); + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) { + he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map); + he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map); + } + + if (band == NL80211_BAND_6GHZ) { + __le16 capa; + + capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE, + IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | + le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, + IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | + le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, + IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); + iftype_data->he_6ghz_capa.capa = capa; + } +} + +static void rtw89_init_eht_cap(struct rtw89_dev *rtwdev, + enum nl80211_band band, + enum nl80211_iftype iftype, + struct ieee80211_sband_iftype_data *iftype_data) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_eht_cap_elem_fixed *eht_cap_elem; + struct ieee80211_eht_mcs_nss_supp *eht_nss; + struct ieee80211_sta_eht_cap *eht_cap; + struct rtw89_hal *hal = &rtwdev->hal; + bool support_320mhz = false; + int sts = 3; + u8 val; + + if (chip->chip_gen == RTW89_CHIP_AX) + return; + + if (band == NL80211_BAND_6GHZ && + chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_320)) + support_320mhz = true; + + eht_cap = &iftype_data->eht_cap; + eht_cap_elem = &eht_cap->eht_cap_elem; + eht_nss = &eht_cap->eht_mcs_nss_supp; + + eht_cap->has_eht = true; + + eht_cap_elem->mac_cap_info[0] = + u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991, + IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); + eht_cap_elem->mac_cap_info[1] = 0; + + eht_cap_elem->phy_cap_info[0] = + IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + if (support_320mhz) + eht_cap_elem->phy_cap_info[0] |= + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + + eht_cap_elem->phy_cap_info[0] |= + u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); + eht_cap_elem->phy_cap_info[1] = + u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)), + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) | + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); + if (support_320mhz) + eht_cap_elem->phy_cap_info[1] |= + u8_encode_bits(sts - 1, + IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); + + eht_cap_elem->phy_cap_info[2] = 0; + + eht_cap_elem->phy_cap_info[3] = + IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | + IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK; + + eht_cap_elem->phy_cap_info[4] = + IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | + u8_encode_bits(1, IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK); + + eht_cap_elem->phy_cap_info[5] = + IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | + u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); + + eht_cap_elem->phy_cap_info[6] = 0; + eht_cap_elem->phy_cap_info[7] = 0; + eht_cap_elem->phy_cap_info[8] = 0; + + val = u8_encode_bits(hal->rx_nss, IEEE80211_EHT_MCS_NSS_RX) | + u8_encode_bits(hal->tx_nss, IEEE80211_EHT_MCS_NSS_TX); + eht_nss->bw._80.rx_tx_mcs9_max_nss = val; + eht_nss->bw._80.rx_tx_mcs11_max_nss = val; + eht_nss->bw._80.rx_tx_mcs13_max_nss = val; + eht_nss->bw._160.rx_tx_mcs9_max_nss = val; + eht_nss->bw._160.rx_tx_mcs11_max_nss = val; + eht_nss->bw._160.rx_tx_mcs13_max_nss = val; + if (support_320mhz) { + eht_nss->bw._320.rx_tx_mcs9_max_nss = val; + eht_nss->bw._320.rx_tx_mcs11_max_nss = val; + eht_nss->bw._320.rx_tx_mcs13_max_nss = val; + } +} + +#define RTW89_SBAND_IFTYPES_NR 2 + +static void rtw89_init_he_eht_cap(struct rtw89_dev *rtwdev, + enum nl80211_band band, + struct ieee80211_supported_band *sband) +{ + struct ieee80211_sband_iftype_data *iftype_data; + enum nl80211_iftype iftype; + int idx = 0; + + iftype_data = kcalloc(RTW89_SBAND_IFTYPES_NR, sizeof(*iftype_data), GFP_KERNEL); + if (!iftype_data) + return; - switch (i) { + for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { + switch (iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: break; @@ -3694,92 +3893,10 @@ static void rtw89_init_he_cap(struct rtw89_dev *rtwdev, break; } - iftype_data[idx].types_mask = BIT(i); - he_cap = &iftype_data[idx].he_cap; - mac_cap_info = he_cap->he_cap_elem.mac_cap_info; - phy_cap_info = he_cap->he_cap_elem.phy_cap_info; - - he_cap->has_he = true; - mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE; - if (i == NL80211_IFTYPE_STATION) - mac_cap_info[1] = IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US; - mac_cap_info[2] = IEEE80211_HE_MAC_CAP2_ALL_ACK | - IEEE80211_HE_MAC_CAP2_BSR; - mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2; - if (i == NL80211_IFTYPE_AP) - mac_cap_info[3] |= IEEE80211_HE_MAC_CAP3_OMI_CONTROL; - mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_OPS | - IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; - if (i == NL80211_IFTYPE_STATION) - mac_cap_info[5] = IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; - if (band == NL80211_BAND_2GHZ) { - phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; - } else { - phy_cap_info[0] = - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; - if (chip->support_bw160) - phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; - } - phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD | - IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US; - phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_NDP_4x_LTF_AND_3_2US | - IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ | - IEEE80211_HE_PHY_CAP2_DOPPLER_TX; - phy_cap_info[3] = IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_16_QAM; - if (i == NL80211_IFTYPE_STATION) - phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_16_QAM | - IEEE80211_HE_PHY_CAP3_DCM_MAX_TX_NSS_2; - if (i == NL80211_IFTYPE_AP) - phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU; - phy_cap_info[4] = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE | - IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4; - if (chip->support_bw160) - phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; - phy_cap_info[5] = no_ng16 ? 0 : - IEEE80211_HE_PHY_CAP5_NG16_SU_FEEDBACK | - IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; - phy_cap_info[6] = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU | - IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | - IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | - IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE; - phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | - IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP7_MAX_NC_1; - phy_cap_info[8] = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_HE_ER_SU_1XLTF_AND_08_US_GI | - IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_996; - if (chip->support_bw160) - phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | - IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; - phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | - IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | - u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US, - IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK); - if (i == NL80211_IFTYPE_STATION) - phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; - he_cap->he_mcs_nss_supp.rx_mcs_80 = cpu_to_le16(mcs_map); - he_cap->he_mcs_nss_supp.tx_mcs_80 = cpu_to_le16(mcs_map); - if (chip->support_bw160) { - he_cap->he_mcs_nss_supp.rx_mcs_160 = cpu_to_le16(mcs_map); - he_cap->he_mcs_nss_supp.tx_mcs_160 = cpu_to_le16(mcs_map); - } - - if (band == NL80211_BAND_6GHZ) { - __le16 capa; + iftype_data[idx].types_mask = BIT(iftype); - capa = le16_encode_bits(IEEE80211_HT_MPDU_DENSITY_NONE, - IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) | - le16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K, - IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) | - le16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454, - IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN); - iftype_data[idx].he_6ghz_capa.capa = capa; - } + rtw89_init_he_cap(rtwdev, band, iftype, &iftype_data[idx]); + rtw89_init_eht_cap(rtwdev, band, iftype, &iftype_data[idx]); idx++; } @@ -3800,7 +3917,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) if (!sband_2ghz) goto err; rtw89_init_ht_cap(rtwdev, &sband_2ghz->ht_cap); - rtw89_init_he_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_2GHZ, sband_2ghz); hw->wiphy->bands[NL80211_BAND_2GHZ] = sband_2ghz; } @@ -3810,7 +3927,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) goto err; rtw89_init_ht_cap(rtwdev, &sband_5ghz->ht_cap); rtw89_init_vht_cap(rtwdev, &sband_5ghz->vht_cap); - rtw89_init_he_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_5GHZ, sband_5ghz); hw->wiphy->bands[NL80211_BAND_5GHZ] = sband_5ghz; } @@ -3818,7 +3935,7 @@ static int rtw89_core_set_supported_band(struct rtw89_dev *rtwdev) sband_6ghz = kmemdup(&rtw89_sband_6ghz, size, GFP_KERNEL); if (!sband_6ghz) goto err; - rtw89_init_he_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz); + rtw89_init_he_eht_cap(rtwdev, NL80211_BAND_6GHZ, sband_6ghz); hw->wiphy->bands[NL80211_BAND_6GHZ] = sband_6ghz; } @@ -3879,7 +3996,7 @@ void rtw89_core_update_beacon_work(struct work_struct *work) rtwdev = rtwvif->rtwdev; mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); mutex_unlock(&rtwdev->mutex); } @@ -3961,6 +4078,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) return ret; rtw89_phy_init_bb_reg(rtwdev); + rtw89_chip_bb_postinit(rtwdev); rtw89_phy_init_rf_reg(rtwdev, false); rtw89_btc_ntfy_init(rtwdev, BTC_MODE_NORMAL); @@ -4078,6 +4196,8 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) rtw89_traffic_stats_init(rtwdev, &rtwdev->stats); rtwdev->hal.rx_fltr = DEFAULT_AX_RX_FLTR; + rtwdev->dbcc_en = false; + rtwdev->mlo_dbcc_mode = MLO_DBCC_NOT_SUPPORT; INIT_WORK(&btc->eapol_notify_work, rtw89_btc_ntfy_eapol_packet_work); INIT_WORK(&btc->arp_notify_work, rtw89_btc_ntfy_arp_packet_work); @@ -4290,6 +4410,7 @@ EXPORT_SYMBOL(rtw89_chip_info_setup); static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) { + const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_hw *hw = rtwdev->hw; struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; @@ -4327,6 +4448,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) /* ref: description of rtw89_mcc_get_tbtt_ofst() in chan.c */ ieee80211_hw_set(hw, TIMING_BEACON_ONLY); + if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) ieee80211_hw_set(hw, CONNECTION_MONITOR); diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index ea6df859ba15..c86b46e7964f 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -32,6 +32,7 @@ extern const struct ieee80211_ops rtw89_ops; #define MASKDWORD 0xffffffff #define RFREG_MASK 0xfffff #define INV_RF_DATA 0xffffffff +#define BYPASS_CR_DATA 0xbabecafe #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) #define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4) @@ -878,7 +879,7 @@ enum rtw89_ps_mode { #define RTW89_5G_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1) #define RTW89_6G_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) #define RTW89_BYR_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) -#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_160 + 1) +#define RTW89_PPE_BW_NUM (RTW89_CHANNEL_WIDTH_320 + 1) enum rtw89_ru_bandwidth { RTW89_RU26 = 0, @@ -2875,7 +2876,7 @@ struct rtw89_ba_cam_entry { #define RTW89_MAX_ADDR_CAM_NUM 128 #define RTW89_MAX_BSSID_CAM_NUM 20 #define RTW89_MAX_SEC_CAM_NUM 128 -#define RTW89_MAX_BA_CAM_NUM 8 +#define RTW89_MAX_BA_CAM_NUM 24 #define RTW89_SEC_CAM_IN_ADDR_CAM 7 struct rtw89_addr_cam_entry { @@ -2932,6 +2933,7 @@ struct rtw89_sta { struct ewma_evm evm_min[RF_PATH_MAX]; struct ewma_evm evm_max[RF_PATH_MAX]; struct rtw89_ampdu_params ampdu_params[IEEE80211_NUM_TIDS]; + DECLARE_BITMAP(ampdu_map, IEEE80211_NUM_TIDS); struct ieee80211_rx_status rx_status; u16 rx_hw_rate; __le32 htc_template; @@ -3131,6 +3133,7 @@ struct rtw89_chip_ops { int (*enable_bb_rf)(struct rtw89_dev *rtwdev); int (*disable_bb_rf)(struct rtw89_dev *rtwdev); void (*bb_preinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); + void (*bb_postinit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void (*bb_reset)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); void (*bb_sethw)(struct rtw89_dev *rtwdev); @@ -3196,6 +3199,22 @@ struct rtw89_chip_ops { int (*h2c_dctl_sec_cam)(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); + int (*h2c_default_cmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); + int (*h2c_assoc_cmac_tbl)(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + int (*h2c_ampdu_cmac_tbl)(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); + int (*h2c_update_beacon)(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); + int (*h2c_ba_cam)(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params); void (*btc_set_rfe)(struct rtw89_dev *rtwdev); void (*btc_init_cfg)(struct rtw89_dev *rtwdev); @@ -3225,6 +3244,20 @@ enum rtw89_dma_ch { RTW89_DMA_CH_NUM = 13 }; +#define MLO_MODE_FOR_BB0_BB1_RF(bb0, bb1, rf) ((rf) << 12 | (bb1) << 4 | (bb0)) + +enum rtw89_mlo_dbcc_mode { + MLO_DBCC_NOT_SUPPORT = 1, + MLO_0_PLUS_2_1RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 1), + MLO_0_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(0, 2, 2), + MLO_1_PLUS_1_1RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 1), + MLO_1_PLUS_1_2RF = MLO_MODE_FOR_BB0_BB1_RF(1, 1, 2), + MLO_2_PLUS_0_1RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 1), + MLO_2_PLUS_0_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 0, 2), + MLO_2_PLUS_2_2RF = MLO_MODE_FOR_BB0_BB1_RF(2, 2, 2), + DBCC_LEGACY = 0xffffffff, +}; + enum rtw89_qta_mode { RTW89_QTA_SCC, RTW89_QTA_DLFW, @@ -3713,7 +3746,7 @@ struct rtw89_chip_info { u32 rf_base_addr[2]; u8 support_chanctx_num; u8 support_bands; - bool support_bw160; + u16 support_bandwidths; bool support_unii4; bool ul_tb_waveform_ctrl; bool ul_tb_pwr_diff; @@ -3897,6 +3930,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_DEEP_PS, RTW89_FW_FEATURE_NO_LPS_PG, RTW89_FW_FEATURE_BEACON_FILTER, + RTW89_FW_FEATURE_MACID_PAUSE_SLEEP, }; struct rtw89_fw_suit { @@ -4589,6 +4623,7 @@ struct rtw89_hw_scan_info { struct ieee80211_vif *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct rtw89_chan op_chan; + bool abort; u32 last_chan_idx; }; @@ -4605,6 +4640,48 @@ enum rtw89_phy_bb_gain_band { RTW89_BB_GAIN_BAND_NR, }; +enum rtw89_phy_gain_band_be { + RTW89_BB_GAIN_BAND_2G_BE = 0, + RTW89_BB_GAIN_BAND_5G_L_BE = 1, + RTW89_BB_GAIN_BAND_5G_M_BE = 2, + RTW89_BB_GAIN_BAND_5G_H_BE = 3, + RTW89_BB_GAIN_BAND_6G_L0_BE = 4, + RTW89_BB_GAIN_BAND_6G_L1_BE = 5, + RTW89_BB_GAIN_BAND_6G_M0_BE = 6, + RTW89_BB_GAIN_BAND_6G_M1_BE = 7, + RTW89_BB_GAIN_BAND_6G_H0_BE = 8, + RTW89_BB_GAIN_BAND_6G_H1_BE = 9, + RTW89_BB_GAIN_BAND_6G_UH0_BE = 10, + RTW89_BB_GAIN_BAND_6G_UH1_BE = 11, + + RTW89_BB_GAIN_BAND_NR_BE, +}; + +enum rtw89_phy_bb_bw_be { + RTW89_BB_BW_20_40 = 0, + RTW89_BB_BW_80_160_320 = 1, + + RTW89_BB_BW_NR_BE, +}; + +enum rtw89_bw20_sc { + RTW89_BW20_SC_20M = 1, + RTW89_BW20_SC_40M = 2, + RTW89_BW20_SC_80M = 4, + RTW89_BW20_SC_160M = 8, + RTW89_BW20_SC_320M = 16, +}; + +enum rtw89_cmac_table_bw { + RTW89_CMAC_BW_20M = 0, + RTW89_CMAC_BW_40M = 1, + RTW89_CMAC_BW_80M = 2, + RTW89_CMAC_BW_160M = 3, + RTW89_CMAC_BW_320M = 4, + + RTW89_CMAC_BW_NR, +}; + enum rtw89_phy_bb_rxsc_num { RTW89_BB_RXSC_NUM_40 = 9, /* SC: 0, 1~8 */ RTW89_BB_RXSC_NUM_80 = 13, /* SC: 0, 1~8, 9~12 */ @@ -4627,6 +4704,27 @@ struct rtw89_phy_bb_gain_info { [RTW89_BB_RXSC_NUM_160]; }; +struct rtw89_phy_bb_gain_info_be { + s8 lna_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX] + [LNA_GAIN_NUM]; + s8 tia_gain[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE][RF_PATH_MAX] + [TIA_GAIN_NUM]; + s8 lna_gain_bypass[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM]; + s8 lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM]; + s8 tia_lna_op1db[RTW89_BB_GAIN_BAND_NR_BE][RTW89_BB_BW_NR_BE] + [RF_PATH_MAX][LNA_GAIN_NUM + 1]; + s8 rpl_ofst_20[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_20M]; + s8 rpl_ofst_40[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_40M]; + s8 rpl_ofst_80[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_80M]; + s8 rpl_ofst_160[RTW89_BB_GAIN_BAND_NR_BE][RF_PATH_MAX] + [RTW89_BW20_SC_160M]; +}; + struct rtw89_phy_efuse_gain { bool offset_valid; bool comp_valid; @@ -4757,6 +4855,7 @@ struct rtw89_dev { const struct ieee80211_ops *ops; bool dbcc_en; + enum rtw89_mlo_dbcc_mode mlo_dbcc_mode; struct rtw89_hw_scan_info scan_info; const struct rtw89_chip_info *chip; const struct rtw89_pci_info *pci_info; @@ -4824,7 +4923,10 @@ struct rtw89_dev { struct rtw89_env_monitor_info env_monitor; struct rtw89_dig_info dig; struct rtw89_phy_ch_info ch_info; - struct rtw89_phy_bb_gain_info bb_gain; + union { + struct rtw89_phy_bb_gain_info ax; + struct rtw89_phy_bb_gain_info_be be; + } bb_gain; struct rtw89_phy_efuse_gain efuse_gain; struct rtw89_phy_ul_tb_info ul_tb_info; struct rtw89_antdiv_info antdiv; @@ -5446,6 +5548,20 @@ void rtw89_chip_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) chip->ops->bb_preinit(rtwdev, phy_idx); } +static inline +void rtw89_chip_bb_postinit(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->bb_postinit) + return; + + chip->ops->bb_postinit(rtwdev, RTW89_PHY_0); + + if (rtwdev->dbcc_en) + chip->ops->bb_postinit(rtwdev, RTW89_PHY_1); +} + static inline void rtw89_chip_bb_sethw(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; @@ -5750,6 +5866,18 @@ out: rcu_read_unlock(); } +static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev) +{ + switch (rtwdev->mlo_dbcc_mode) { + case MLO_1_PLUS_1_1RF: + case MLO_1_PLUS_1_2RF: + case DBCC_LEGACY: + return true; + default: + return false; + } +} + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); int rtw89_h2c_tx(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 09684cea9731..e49360e29faf 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -458,6 +458,7 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -1485,13 +1486,108 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v1); -#define H2C_BA_CAM_LEN 8 +int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct rtw89_h2c_dctlinfo_ud_v2 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for dctl sec cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; + + rtw89_cam_fill_dctl_sec_cam_info_v2(rtwdev, rtwvif, rtwsta, h2c); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V2, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_dctl_sec_cam_v2); + +int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_dctlinfo_ud_v2 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for dctl v2\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_dctlinfo_ud_v2 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, DCTLINFO_V2_C0_MACID) | + le32_encode_bits(1, DCTLINFO_V2_C0_OP); + + h2c->m0 = cpu_to_le32(DCTLINFO_V2_W0_ALL); + h2c->m1 = cpu_to_le32(DCTLINFO_V2_W1_ALL); + h2c->m2 = cpu_to_le32(DCTLINFO_V2_W2_ALL); + h2c->m3 = cpu_to_le32(DCTLINFO_V2_W3_ALL); + h2c->m4 = cpu_to_le32(DCTLINFO_V2_W4_ALL); + h2c->m5 = cpu_to_le32(DCTLINFO_V2_W5_ALL); + h2c->m6 = cpu_to_le32(DCTLINFO_V2_W6_ALL); + h2c->m7 = cpu_to_le32(DCTLINFO_V2_W7_ALL); + h2c->m8 = cpu_to_le32(DCTLINFO_V2_W8_ALL); + h2c->m9 = cpu_to_le32(DCTLINFO_V2_W9_ALL); + h2c->m10 = cpu_to_le32(DCTLINFO_V2_W10_ALL); + h2c->m11 = cpu_to_le32(DCTLINFO_V2_W11_ALL); + h2c->m12 = cpu_to_le32(DCTLINFO_V2_W12_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_DCTLINFO_UD_V2, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_dmac_tbl_v2); + int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_h2c_ba_cam *h2c; u8 macid = rtwsta->mac_id; + u32 len = sizeof(*h2c); struct sk_buff *skb; u8 entry_idx; int ret; @@ -1509,32 +1605,34 @@ int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, return 0; } - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n"); return -ENOMEM; } - skb_put(skb, H2C_BA_CAM_LEN); - SET_BA_CAM_MACID(skb->data, macid); + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam *)skb->data; + + h2c->w0 = le32_encode_bits(macid, RTW89_H2C_BA_CAM_W0_MACID); if (chip->bacam_ver == RTW89_BACAM_V0_EXT) - SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); + h2c->w1 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1); else - SET_BA_CAM_ENTRY_IDX(skb->data, entry_idx); + h2c->w0 |= le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W0_ENTRY_IDX); if (!valid) goto end; - SET_BA_CAM_VALID(skb->data, valid); - SET_BA_CAM_TID(skb->data, params->tid); + h2c->w0 |= le32_encode_bits(valid, RTW89_H2C_BA_CAM_W0_VALID) | + le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_W0_TID); if (params->buf_size > 64) - SET_BA_CAM_BMAP_SIZE(skb->data, 4); + h2c->w0 |= le32_encode_bits(4, RTW89_H2C_BA_CAM_W0_BMAP_SIZE); else - SET_BA_CAM_BMAP_SIZE(skb->data, 0); + h2c->w0 |= le32_encode_bits(0, RTW89_H2C_BA_CAM_W0_BMAP_SIZE); /* If init req is set, hw will set the ssn */ - SET_BA_CAM_INIT_REQ(skb->data, 1); - SET_BA_CAM_SSN(skb->data, params->ssn); + h2c->w0 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_INIT_REQ) | + le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_W0_SSN); if (chip->bacam_ver == RTW89_BACAM_V0_EXT) { - SET_BA_CAM_STD_EN(skb->data, 1); - SET_BA_CAM_BAND(skb->data, rtwvif->mac_idx); + h2c->w1 |= le32_encode_bits(1, RTW89_H2C_BA_CAM_W1_STD_EN) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BA_CAM_W1_BAND); } end: @@ -1542,7 +1640,7 @@ end: H2C_CAT_MAC, H2C_CL_BA_CAM, H2C_FUNC_MAC_BA_CAM, 0, 1, - H2C_BA_CAM_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1556,31 +1654,35 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam); static int rtw89_fw_h2c_init_ba_cam_v0_ext(struct rtw89_dev *rtwdev, u8 entry_idx, u8 uid) { + struct rtw89_h2c_ba_cam *h2c; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_BA_CAM_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for dynamic h2c ba cam\n"); return -ENOMEM; } - skb_put(skb, H2C_BA_CAM_LEN); + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam *)skb->data; - SET_BA_CAM_VALID(skb->data, 1); - SET_BA_CAM_ENTRY_IDX_V1(skb->data, entry_idx); - SET_BA_CAM_UID(skb->data, uid); - SET_BA_CAM_BAND(skb->data, 0); - SET_BA_CAM_STD_EN(skb->data, 0); + h2c->w0 = le32_encode_bits(1, RTW89_H2C_BA_CAM_W0_VALID); + h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1) | + le32_encode_bits(uid, RTW89_H2C_BA_CAM_W1_UID) | + le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_BAND) | + le32_encode_bits(0, RTW89_H2C_BA_CAM_W1_STD_EN); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_BA_CAM, H2C_FUNC_MAC_BA_CAM, 0, 1, - H2C_BA_CAM_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -1609,6 +1711,120 @@ void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev) } } +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif *rtwvif = rtwsta->rtwvif; + struct rtw89_h2c_ba_cam_v1 *h2c; + u8 macid = rtwsta->mac_id; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 entry_idx; + u8 bmap_size; + int ret; + + ret = valid ? + rtw89_core_acquire_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx) : + rtw89_core_release_sta_ba_entry(rtwdev, rtwsta, params->tid, &entry_idx); + if (ret) { + /* it still works even if we don't have static BA CAM, because + * hardware can create dynamic BA CAM automatically. + */ + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "failed to %s entry tid=%d for h2c ba cam\n", + valid ? "alloc" : "free", params->tid); + return 0; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam_v1 *)skb->data; + + if (params->buf_size > 512) + bmap_size = 10; + else if (params->buf_size > 256) + bmap_size = 8; + else if (params->buf_size > 64) + bmap_size = 4; + else + bmap_size = 0; + + h2c->w0 = le32_encode_bits(valid, RTW89_H2C_BA_CAM_V1_W0_VALID) | + le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W0_INIT_REQ) | + le32_encode_bits(macid, RTW89_H2C_BA_CAM_V1_W0_MACID_MASK) | + le32_encode_bits(params->tid, RTW89_H2C_BA_CAM_V1_W0_TID_MASK) | + le32_encode_bits(bmap_size, RTW89_H2C_BA_CAM_V1_W0_BMAP_SIZE_MASK) | + le32_encode_bits(params->ssn, RTW89_H2C_BA_CAM_V1_W0_SSN_MASK); + + entry_idx += chip->bacam_dynamic_num; /* std entry right after dynamic ones */ + h2c->w1 = le32_encode_bits(entry_idx, RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK) | + le32_encode_bits(1, RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN) | + le32_encode_bits(!!rtwvif->mac_idx, RTW89_H2C_BA_CAM_V1_W1_BAND_SEL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_BA_CAM, + H2C_FUNC_MAC_BA_CAM_V1, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_ba_cam_v1); + +int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, + u8 offset, u8 mac_idx) +{ + struct rtw89_h2c_ba_cam_init *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c ba cam init\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_ba_cam_init *)skb->data; + + h2c->w0 = le32_encode_bits(users, RTW89_H2C_BA_CAM_INIT_USERS_MASK) | + le32_encode_bits(offset, RTW89_H2C_BA_CAM_INIT_OFFSET_MASK) | + le32_encode_bits(mac_idx, RTW89_H2C_BA_CAM_INIT_BAND_SEL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, + H2C_CL_BA_CAM, + H2C_FUNC_MAC_BA_CAM_INIT, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + #define H2C_LOG_CFG_LEN 12 int rtw89_fw_h2c_fw_log(struct rtw89_dev *rtwdev, bool enable) { @@ -1892,11 +2108,12 @@ static void __rtw89_fw_h2c_set_tx_path(struct rtw89_dev *rtwdev, #define H2C_CMC_TBL_LEN 68 int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) { const struct rtw89_chip_info *chip = rtwdev->chip; + u8 macid = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; struct sk_buff *skb; - u8 macid = rtwvif->mac_id; int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_CMC_TBL_LEN); @@ -1937,6 +2154,91 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl); + +int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w0 = le32_encode_bits(4, CCTLINFO_G7_W0_DATARATE); + h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_ALL); + + h2c->w1 = le32_encode_bits(4, CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE) | + le32_encode_bits(0xa, CCTLINFO_G7_W1_RTSRATE) | + le32_encode_bits(4, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_ALL); + + h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_ALL); + + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_ALL); + + h2c->w4 = le32_encode_bits(0xFFFF, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ALL); + + h2c->w5 = le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) | + le32_encode_bits(2, CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_ALL); + + h2c->w6 = le32_encode_bits(0xb, CCTLINFO_G7_W6_RESP_REF_RATE); + h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ALL); + + h2c->w7 = le32_encode_bits(1, CCTLINFO_G7_W7_NC) | + le32_encode_bits(1, CCTLINFO_G7_W7_NR) | + le32_encode_bits(1, CCTLINFO_G7_W7_CB) | + le32_encode_bits(0x1, CCTLINFO_G7_W7_CSI_PARA_EN) | + le32_encode_bits(0xb, CCTLINFO_G7_W7_CSI_FIX_RATE); + h2c->m7 = cpu_to_le32(CCTLINFO_G7_W7_ALL); + + h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_ALL); + + h2c->w14 = le32_encode_bits(0, CCTLINFO_G7_W14_VO_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W14_VI_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W14_BE_CURR_RATE_L); + h2c->m14 = cpu_to_le32(CCTLINFO_G7_W14_ALL); + + h2c->w15 = le32_encode_bits(0, CCTLINFO_G7_W15_BE_CURR_RATE_H) | + le32_encode_bits(0, CCTLINFO_G7_W15_BK_CURR_RATE) | + le32_encode_bits(0, CCTLINFO_G7_W15_MGNT_CURR_RATE); + h2c->m15 = cpu_to_le32(CCTLINFO_G7_W15_ALL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_default_cmac_tbl_g7); static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, struct ieee80211_sta *sta, u8 *pads) @@ -1950,9 +2252,6 @@ static void __get_sta_he_pkt_padding(struct rtw89_dev *rtwdev, u16 ppe; int i; - if (!sta->deflink.he_cap.has_he) - return; - ppe_th = FIELD_GET(IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, sta->deflink.he_cap.he_cap_elem.phy_cap_info[6]); if (!ppe_th) { @@ -2011,7 +2310,7 @@ int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, int ret; memset(pads, 0, sizeof(pads)); - if (sta) + if (sta && sta->deflink.he_cap.has_he) __get_sta_he_pkt_padding(rtwdev, sta, pads); if (vif->p2p) @@ -2073,6 +2372,244 @@ fail: return ret; } +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl); + +static void __get_sta_eht_pkt_padding(struct rtw89_dev *rtwdev, + struct ieee80211_sta *sta, u8 *pads) +{ + u8 nss = min(sta->deflink.rx_nss, rtwdev->hal.tx_nss) - 1; + u16 ppe_thres_hdr; + u8 ppe16, ppe8; + u8 n, idx, sh; + u8 ru_bitmap; + bool ppe_th; + u16 ppe; + int i; + + ppe_th = !!u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT); + if (!ppe_th) { + u8 pad; + + pad = u8_get_bits(sta->deflink.eht_cap.eht_cap_elem.phy_cap_info[5], + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK); + + for (i = 0; i < RTW89_PPE_BW_NUM; i++) + pads[i] = pad; + + return; + } + + ppe_thres_hdr = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres); + ru_bitmap = u16_get_bits(ppe_thres_hdr, + IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK); + n = hweight8(ru_bitmap); + n = IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE + + (n * IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2) * nss; + + for (i = 0; i < RTW89_PPE_BW_NUM; i++) { + if (!(ru_bitmap & BIT(i))) { + pads[i] = 1; + continue; + } + + idx = n >> 3; + sh = n & 7; + n += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE * 2; + + ppe = get_unaligned_le16(sta->deflink.eht_cap.eht_ppe_thres + idx); + ppe16 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; + sh += IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE; + ppe8 = (ppe >> sh) & IEEE80211_PPE_THRES_NSS_MASK; + + if (ppe16 != 7 && ppe8 == 7) + pads[i] = 2; + else if (ppe8 != 7) + pads[i] = 1; + else + pads[i] = 0; + } +} + +int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; + struct rtw89_sta *rtwsta = sta_to_rtwsta_safe(sta); + u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u8 pads[RTW89_PPE_BW_NUM]; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 lowest_rate; + int ret; + + memset(pads, 0, sizeof(pads)); + if (sta) { + if (sta->deflink.eht_cap.has_eht) + __get_sta_eht_pkt_padding(rtwdev, sta, pads); + else if (sta->deflink.he_cap.has_he) + __get_sta_he_pkt_padding(rtwdev, sta, pads); + } + + if (vif->p2p) + lowest_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + lowest_rate = RTW89_HW_RATE_CCK1; + else + lowest_rate = RTW89_HW_RATE_OFDM6; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w0 = le32_encode_bits(1, CCTLINFO_G7_W0_DISRTSFB) | + le32_encode_bits(1, CCTLINFO_G7_W0_DISDATAFB); + h2c->m0 = cpu_to_le32(CCTLINFO_G7_W0_DISRTSFB | + CCTLINFO_G7_W0_DISDATAFB); + + h2c->w1 = le32_encode_bits(lowest_rate, CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + h2c->m1 = cpu_to_le32(CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE); + + h2c->w2 = le32_encode_bits(0, CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL); + h2c->m2 = cpu_to_le32(CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL); + + h2c->w3 = le32_encode_bits(0, CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL); + + h2c->w4 = le32_encode_bits(rtwvif->port, CCTLINFO_G7_W4_MULTI_PORT_ID); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_MULTI_PORT_ID); + + if (rtwvif->net_type == RTW89_NET_TYPE_AP_MODE) { + h2c->w4 |= le32_encode_bits(0, CCTLINFO_G7_W4_DATA_DCM); + h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_DATA_DCM); + } + + if (vif->bss_conf.eht_support) { + h2c->w4 |= le32_encode_bits(~vif->bss_conf.eht_puncturing, + CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 |= cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); + } + + h2c->w5 = le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_20], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_40], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_80], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_160], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3) | + le32_encode_bits(pads[RTW89_CHANNEL_WIDTH_320], + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + h2c->m5 = cpu_to_le32(CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 | + CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4); + + h2c->w6 = le32_encode_bits(vif->type == NL80211_IFTYPE_STATION ? 1 : 0, + CCTLINFO_G7_W6_ULDL); + h2c->m6 = cpu_to_le32(CCTLINFO_G7_W6_ULDL); + + if (sta) { + h2c->w8 = le32_encode_bits(sta->deflink.he_cap.has_he, + CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); + h2c->m8 = cpu_to_le32(CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT); + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_assoc_cmac_tbl_g7); + +int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u16 agg_num = 0; + u8 ba_bmap = 0; + int ret; + u8 tid; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for ampdu cmac g7\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + for_each_set_bit(tid, rtwsta->ampdu_map, IEEE80211_NUM_TIDS) { + if (agg_num == 0) + agg_num = rtwsta->ampdu_params[tid].agg_num; + else + agg_num = min(agg_num, rtwsta->ampdu_params[tid].agg_num); + } + + if (agg_num <= 0x20) + ba_bmap = 3; + else if (agg_num > 0x20 && agg_num <= 0x40) + ba_bmap = 0; + else if (agg_num > 0x40 && agg_num <= 0x80) + ba_bmap = 1; + else if (agg_num > 0x80 && agg_num <= 0x100) + ba_bmap = 2; + else if (agg_num > 0x100 && agg_num <= 0x200) + ba_bmap = 4; + else if (agg_num > 0x200 && agg_num <= 0x400) + ba_bmap = 5; + + h2c->c0 = le32_encode_bits(rtwsta->mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w3 = le32_encode_bits(ba_bmap, CCTLINFO_G7_W3_BA_BMAP); + h2c->m3 = cpu_to_le32(CCTLINFO_G7_W3_BA_BMAP); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_ampdu_cmac_tbl_g7); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta) @@ -2155,18 +2692,20 @@ fail: return ret; } -#define H2C_BCN_BASE_LEN 12 int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) { - struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif->sub_entity_idx); - struct sk_buff *skb; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_h2c_bcn_upd *h2c; struct sk_buff *skb_beacon; - u16 tim_offset; + struct ieee80211_hdr *hdr; + u32 len = sizeof(*h2c); + struct sk_buff *skb; int bcn_total_len; u16 beacon_rate; + u16 tim_offset; void *noa_data; u8 noa_len; int ret; @@ -2192,23 +2731,27 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, skb_put_data(skb_beacon, noa_data, noa_len); } - bcn_total_len = H2C_BCN_BASE_LEN + skb_beacon->len; + hdr = (struct ieee80211_hdr *)skb_beacon; + tim_offset -= ieee80211_hdrlen(hdr->frame_control); + + bcn_total_len = len + skb_beacon->len; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); dev_kfree_skb_any(skb_beacon); return -ENOMEM; } - skb_put(skb, H2C_BCN_BASE_LEN); + skb_put(skb, len); + h2c = (struct rtw89_h2c_bcn_upd *)skb->data; - SET_BCN_UPD_PORT(skb->data, rtwvif->port); - SET_BCN_UPD_MBSSID(skb->data, 0); - SET_BCN_UPD_BAND(skb->data, rtwvif->mac_idx); - SET_BCN_UPD_GRP_IE_OFST(skb->data, tim_offset); - SET_BCN_UPD_MACID(skb->data, rtwvif->mac_id); - SET_BCN_UPD_SSN_SEL(skb->data, RTW89_MGMT_HW_SSN_SEL); - SET_BCN_UPD_SSN_MODE(skb->data, RTW89_MGMT_HW_SEQ_MODE); - SET_BCN_UPD_RATE(skb->data, beacon_rate); + h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_W0_PORT) | + le32_encode_bits(0, RTW89_H2C_BCN_UPD_W0_MBSSID) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_W0_BAND) | + le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST); + h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_W1_MACID) | + le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_W1_SSN_SEL) | + le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_W1_SSN_MODE) | + le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_W1_RATE); skb_put_data(skb, skb_beacon->data, skb_beacon->len); dev_kfree_skb_any(skb_beacon); @@ -2227,6 +2770,90 @@ int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, return 0; } +EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon); + +int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_h2c_bcn_upd_be *h2c; + struct sk_buff *skb_beacon; + struct ieee80211_hdr *hdr; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int bcn_total_len; + u16 beacon_rate; + u16 tim_offset; + void *noa_data; + u8 noa_len; + int ret; + + if (vif->p2p) + beacon_rate = RTW89_HW_RATE_OFDM6; + else if (chan->band_type == RTW89_BAND_2G) + beacon_rate = RTW89_HW_RATE_CCK1; + else + beacon_rate = RTW89_HW_RATE_OFDM6; + + skb_beacon = ieee80211_beacon_get_tim(rtwdev->hw, vif, &tim_offset, + NULL, 0); + if (!skb_beacon) { + rtw89_err(rtwdev, "failed to get beacon skb\n"); + return -ENOMEM; + } + + noa_len = rtw89_p2p_noa_fetch(rtwvif, &noa_data); + if (noa_len && + (noa_len <= skb_tailroom(skb_beacon) || + pskb_expand_head(skb_beacon, 0, noa_len, GFP_KERNEL) == 0)) { + skb_put_data(skb_beacon, noa_data, noa_len); + } + + hdr = (struct ieee80211_hdr *)skb_beacon; + tim_offset -= ieee80211_hdrlen(hdr->frame_control); + + bcn_total_len = len + skb_beacon->len; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, bcn_total_len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); + dev_kfree_skb_any(skb_beacon); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_bcn_upd_be *)skb->data; + + h2c->w0 = le32_encode_bits(rtwvif->port, RTW89_H2C_BCN_UPD_BE_W0_PORT) | + le32_encode_bits(0, RTW89_H2C_BCN_UPD_BE_W0_MBSSID) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_BCN_UPD_BE_W0_BAND) | + le32_encode_bits(tim_offset | BIT(7), RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST); + h2c->w1 = le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCN_UPD_BE_W1_MACID) | + le32_encode_bits(RTW89_MGMT_HW_SSN_SEL, RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL) | + le32_encode_bits(RTW89_MGMT_HW_SEQ_MODE, RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE) | + le32_encode_bits(beacon_rate, RTW89_H2C_BCN_UPD_BE_W1_RATE); + + skb_put_data(skb, skb_beacon->data, skb_beacon->len); + dev_kfree_skb_any(skb_beacon); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_BCN_UPD_BE, 0, 1, + bcn_total_len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; + +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); #define H2C_ROLE_MAINTAIN_LEN 4 int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, @@ -2277,45 +2904,93 @@ fail: return ret; } -#define H2C_JOIN_INFO_LEN 4 +static enum rtw89_fw_sta_type +rtw89_fw_get_sta_type(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + struct ieee80211_sta *sta = rtwsta_to_sta_safe(rtwsta); + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + + if (!sta) + goto by_vif; + + if (sta->deflink.eht_cap.has_eht) + return RTW89_FW_BE_STA; + else if (sta->deflink.he_cap.has_he) + return RTW89_FW_AX_STA; + else + return RTW89_FW_N_AC_STA; + +by_vif: + if (vif->bss_conf.eht_support) + return RTW89_FW_BE_STA; + else if (vif->bss_conf.he_support) + return RTW89_FW_AX_STA; + else + return RTW89_FW_N_AC_STA; +} + int rtw89_fw_h2c_join_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta, bool dis_conn) { struct sk_buff *skb; u8 mac_id = rtwsta ? rtwsta->mac_id : rtwvif->mac_id; u8 self_role = rtwvif->self_role; + enum rtw89_fw_sta_type sta_type; u8 net_type = rtwvif->net_type; + struct rtw89_h2c_join_v1 *h2c_v1; + struct rtw89_h2c_join *h2c; + u32 len = sizeof(*h2c); + bool format_v1 = false; int ret; + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { + len = sizeof(*h2c_v1); + format_v1 = true; + } + if (net_type == RTW89_NET_TYPE_AP_MODE && rtwsta) { self_role = RTW89_SELF_ROLE_AP_CLIENT; net_type = dis_conn ? RTW89_NET_TYPE_NO_LINK : net_type; } - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); return -ENOMEM; } - skb_put(skb, H2C_JOIN_INFO_LEN); - SET_JOININFO_MACID(skb->data, mac_id); - SET_JOININFO_OP(skb->data, dis_conn); - SET_JOININFO_BAND(skb->data, rtwvif->mac_idx); - SET_JOININFO_WMM(skb->data, rtwvif->wmm); - SET_JOININFO_TGR(skb->data, rtwvif->trigger); - SET_JOININFO_ISHESTA(skb->data, 0); - SET_JOININFO_DLBW(skb->data, 0); - SET_JOININFO_TF_MAC_PAD(skb->data, 0); - SET_JOININFO_DL_T_PE(skb->data, 0); - SET_JOININFO_PORT_ID(skb->data, rtwvif->port); - SET_JOININFO_NET_TYPE(skb->data, net_type); - SET_JOININFO_WIFI_ROLE(skb->data, rtwvif->wifi_role); - SET_JOININFO_SELF_ROLE(skb->data, self_role); + skb_put(skb, len); + h2c = (struct rtw89_h2c_join *)skb->data; + + h2c->w0 = le32_encode_bits(mac_id, RTW89_H2C_JOININFO_W0_MACID) | + le32_encode_bits(dis_conn, RTW89_H2C_JOININFO_W0_OP) | + le32_encode_bits(rtwvif->mac_idx, RTW89_H2C_JOININFO_W0_BAND) | + le32_encode_bits(rtwvif->wmm, RTW89_H2C_JOININFO_W0_WMM) | + le32_encode_bits(rtwvif->trigger, RTW89_H2C_JOININFO_W0_TGR) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_ISHESTA) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DLBW) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_TF_MAC_PAD) | + le32_encode_bits(0, RTW89_H2C_JOININFO_W0_DL_T_PE) | + le32_encode_bits(rtwvif->port, RTW89_H2C_JOININFO_W0_PORT_ID) | + le32_encode_bits(net_type, RTW89_H2C_JOININFO_W0_NET_TYPE) | + le32_encode_bits(rtwvif->wifi_role, RTW89_H2C_JOININFO_W0_WIFI_ROLE) | + le32_encode_bits(self_role, RTW89_H2C_JOININFO_W0_SELF_ROLE); + + if (!format_v1) + goto done; + + h2c_v1 = (struct rtw89_h2c_join_v1 *)skb->data; + + sta_type = rtw89_fw_get_sta_type(rtwdev, rtwvif, rtwsta); + h2c_v1->w1 = le32_encode_bits(sta_type, RTW89_H2C_JOININFO_W1_STA_TYPE); + h2c_v1->w2 = 0; + +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_MEDIA_RPT, H2C_FUNC_MAC_JOININFO, 0, 1, - H2C_JOIN_INFO_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -2368,24 +3043,49 @@ fail: int rtw89_fw_h2c_macid_pause(struct rtw89_dev *rtwdev, u8 sh, u8 grp, bool pause) { - struct rtw89_fw_macid_pause_grp h2c = {{0}}; - u8 len = sizeof(struct rtw89_fw_macid_pause_grp); + struct rtw89_fw_macid_pause_sleep_grp *h2c_new; + struct rtw89_fw_macid_pause_grp *h2c; + __le32 set = cpu_to_le32(BIT(sh)); + u8 h2c_macid_pause_id; struct sk_buff *skb; + u32 len; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_JOIN_INFO_LEN); + if (RTW89_CHK_FW_FEATURE(MACID_PAUSE_SLEEP, &rtwdev->fw)) { + h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE_SLEEP; + len = sizeof(*h2c_new); + } else { + h2c_macid_pause_id = H2C_FUNC_MAC_MACID_PAUSE; + len = sizeof(*h2c); + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { - rtw89_err(rtwdev, "failed to alloc skb for h2c join\n"); + rtw89_err(rtwdev, "failed to alloc skb for h2c macid pause\n"); return -ENOMEM; } - h2c.mask_grp[grp] = cpu_to_le32(BIT(sh)); - if (pause) - h2c.pause_grp[grp] = cpu_to_le32(BIT(sh)); - skb_put_data(skb, &h2c, len); + skb_put(skb, len); + + if (h2c_macid_pause_id == H2C_FUNC_MAC_MACID_PAUSE_SLEEP) { + h2c_new = (struct rtw89_fw_macid_pause_sleep_grp *)skb->data; + + h2c_new->n[0].pause_mask_grp[grp] = set; + h2c_new->n[0].sleep_mask_grp[grp] = set; + if (pause) { + h2c_new->n[0].pause_grp[grp] = set; + h2c_new->n[0].sleep_grp[grp] = set; + } + } else { + h2c = (struct rtw89_fw_macid_pause_grp *)skb->data; + + h2c->mask_grp[grp] = set; + if (pause) + h2c->pause_grp[grp] = set; + } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, - H2C_FUNC_MAC_MACID_PAUSE, 1, 0, + h2c_macid_pause_id, 1, 0, len); ret = rtw89_h2c_tx(rtwdev, skb, false); @@ -2516,6 +3216,8 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct ieee80211_bss_conf *bss_conf = vif ? &vif->bss_conf : NULL; + s32 thold = RTW89_DEFAULT_CQM_THOLD; + u32 hyst = RTW89_DEFAULT_CQM_HYST; struct rtw89_h2c_bcnfltr *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; @@ -2536,14 +3238,19 @@ int rtw89_fw_h2c_set_bcn_fltr_cfg(struct rtw89_dev *rtwdev, skb_put(skb, len); h2c = (struct rtw89_h2c_bcnfltr *)skb->data; + if (bss_conf->cqm_rssi_hyst) + hyst = bss_conf->cqm_rssi_hyst; + if (bss_conf->cqm_rssi_thold) + thold = bss_conf->cqm_rssi_thold; + h2c->w0 = le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_RSSI) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_BCN) | le32_encode_bits(connect, RTW89_H2C_BCNFLTR_W0_MON_EN) | le32_encode_bits(RTW89_BCN_FLTR_OFFLOAD_MODE_DEFAULT, RTW89_H2C_BCNFLTR_W0_MODE) | le32_encode_bits(RTW89_BCN_LOSS_CNT, RTW89_H2C_BCNFLTR_W0_BCN_LOSS_CNT) | - le32_encode_bits(bss_conf->cqm_rssi_hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | - le32_encode_bits(bss_conf->cqm_rssi_thold + MAX_RSSI, + le32_encode_bits(hyst, RTW89_H2C_BCNFLTR_W0_RSSI_HYST) | + le32_encode_bits(thold + MAX_RSSI, RTW89_H2C_BCNFLTR_W0_RSSI_THRESHOLD) | le32_encode_bits(rtwvif->mac_id, RTW89_H2C_BCNFLTR_W0_MAC_ID); @@ -3296,62 +4003,67 @@ int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, return 0; } -#define H2C_LEN_SCAN_LIST_OFFLOAD 4 -int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, +int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list) { struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_h2c_chinfo_elem *elem; struct rtw89_mac_chinfo *ch_info; + struct rtw89_h2c_chinfo *h2c; struct sk_buff *skb; - int skb_len = H2C_LEN_SCAN_LIST_OFFLOAD + len * RTW89_MAC_CHINFO_SIZE; unsigned int cond; - u8 *cmd; + int skb_len; int ret; + static_assert(sizeof(*elem) == RTW89_MAC_CHINFO_SIZE); + + skb_len = struct_size(h2c, elem, ch_num); skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, skb_len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c scan list\n"); return -ENOMEM; } - skb_put(skb, H2C_LEN_SCAN_LIST_OFFLOAD); - cmd = skb->data; + skb_put(skb, sizeof(*h2c)); + h2c = (struct rtw89_h2c_chinfo *)skb->data; - RTW89_SET_FWCMD_SCANOFLD_CH_NUM(cmd, len); - /* in unit of 4 bytes */ - RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(cmd, RTW89_MAC_CHINFO_SIZE / 4); + h2c->ch_num = ch_num; + h2c->elem_size = sizeof(*elem) / 4; /* in unit of 4 bytes */ list_for_each_entry(ch_info, chan_list, list) { - cmd = skb_put(skb, RTW89_MAC_CHINFO_SIZE); - - RTW89_SET_FWCMD_CHINFO_PERIOD(cmd, ch_info->period); - RTW89_SET_FWCMD_CHINFO_DWELL(cmd, ch_info->dwell_time); - RTW89_SET_FWCMD_CHINFO_CENTER_CH(cmd, ch_info->central_ch); - RTW89_SET_FWCMD_CHINFO_PRI_CH(cmd, ch_info->pri_ch); - RTW89_SET_FWCMD_CHINFO_BW(cmd, ch_info->bw); - RTW89_SET_FWCMD_CHINFO_ACTION(cmd, ch_info->notify_action); - RTW89_SET_FWCMD_CHINFO_NUM_PKT(cmd, ch_info->num_pkt); - RTW89_SET_FWCMD_CHINFO_TX(cmd, ch_info->tx_pkt); - RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(cmd, ch_info->pause_data); - RTW89_SET_FWCMD_CHINFO_BAND(cmd, ch_info->ch_band); - RTW89_SET_FWCMD_CHINFO_PKT_ID(cmd, ch_info->probe_id); - RTW89_SET_FWCMD_CHINFO_DFS(cmd, ch_info->dfs_ch); - RTW89_SET_FWCMD_CHINFO_TX_NULL(cmd, ch_info->tx_null); - RTW89_SET_FWCMD_CHINFO_RANDOM(cmd, ch_info->rand_seq_num); - RTW89_SET_FWCMD_CHINFO_PKT0(cmd, ch_info->pkt_id[0]); - RTW89_SET_FWCMD_CHINFO_PKT1(cmd, ch_info->pkt_id[1]); - RTW89_SET_FWCMD_CHINFO_PKT2(cmd, ch_info->pkt_id[2]); - RTW89_SET_FWCMD_CHINFO_PKT3(cmd, ch_info->pkt_id[3]); - RTW89_SET_FWCMD_CHINFO_PKT4(cmd, ch_info->pkt_id[4]); - RTW89_SET_FWCMD_CHINFO_PKT5(cmd, ch_info->pkt_id[5]); - RTW89_SET_FWCMD_CHINFO_PKT6(cmd, ch_info->pkt_id[6]); - RTW89_SET_FWCMD_CHINFO_PKT7(cmd, ch_info->pkt_id[7]); + elem = (struct rtw89_h2c_chinfo_elem *)skb_put(skb, sizeof(*elem)); + + elem->w0 = le32_encode_bits(ch_info->period, RTW89_H2C_CHINFO_W0_PERIOD) | + le32_encode_bits(ch_info->dwell_time, RTW89_H2C_CHINFO_W0_DWELL) | + le32_encode_bits(ch_info->central_ch, RTW89_H2C_CHINFO_W0_CENTER_CH) | + le32_encode_bits(ch_info->pri_ch, RTW89_H2C_CHINFO_W0_PRI_CH); + + elem->w1 = le32_encode_bits(ch_info->bw, RTW89_H2C_CHINFO_W1_BW) | + le32_encode_bits(ch_info->notify_action, RTW89_H2C_CHINFO_W1_ACTION) | + le32_encode_bits(ch_info->num_pkt, RTW89_H2C_CHINFO_W1_NUM_PKT) | + le32_encode_bits(ch_info->tx_pkt, RTW89_H2C_CHINFO_W1_TX) | + le32_encode_bits(ch_info->pause_data, RTW89_H2C_CHINFO_W1_PAUSE_DATA) | + le32_encode_bits(ch_info->ch_band, RTW89_H2C_CHINFO_W1_BAND) | + le32_encode_bits(ch_info->probe_id, RTW89_H2C_CHINFO_W1_PKT_ID) | + le32_encode_bits(ch_info->dfs_ch, RTW89_H2C_CHINFO_W1_DFS) | + le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_W1_TX_NULL) | + le32_encode_bits(ch_info->rand_seq_num, RTW89_H2C_CHINFO_W1_RANDOM); + + elem->w2 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_W2_PKT0) | + le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_W2_PKT1) | + le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_W2_PKT2) | + le32_encode_bits(ch_info->pkt_id[3], RTW89_H2C_CHINFO_W2_PKT3); + + elem->w3 = le32_encode_bits(ch_info->pkt_id[4], RTW89_H2C_CHINFO_W3_PKT4) | + le32_encode_bits(ch_info->pkt_id[5], RTW89_H2C_CHINFO_W3_PKT5) | + le32_encode_bits(ch_info->pkt_id[6], RTW89_H2C_CHINFO_W3_PKT6) | + le32_encode_bits(ch_info->pkt_id[7], RTW89_H2C_CHINFO_W3_PKT7); } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_ADD_SCANOFLD_CH, 1, 1, skb_len); - cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH); + cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH; ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { @@ -3410,7 +4122,10 @@ int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, H2C_FUNC_SCANOFLD, 1, 1, len); - cond = RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD); + if (option->enable) + cond = RTW89_SCANOFLD_WAIT_COND_START; + else + cond = RTW89_SCANOFLD_WAIT_COND_STOP; ret = rtw89_h2c_tx_and_wait(rtwdev, skb, wait, cond); if (ret) { @@ -3600,7 +4315,7 @@ static bool rtw89_fw_c2h_chk_atomic(struct rtw89_dev *rtwdev, default: return false; case RTW89_C2H_CAT_MAC: - return rtw89_mac_c2h_chk_atomic(rtwdev, class, func); + return rtw89_mac_c2h_chk_atomic(rtwdev, c2h, class, func); case RTW89_C2H_CAT_OUTSRC: return rtw89_phy_c2h_chk_atomic(rtwdev, class, func); } @@ -4154,9 +4869,11 @@ void rtw89_hw_scan_start(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_get_channel(rtwdev, rtwvif, &rtwdev->scan_info.op_chan); rtwdev->scan_info.scanning_vif = vif; rtwdev->scan_info.last_chan_idx = 0; + rtwdev->scan_info.abort = false; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; ieee80211_stop_queues(rtwdev->hw); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, false); if (req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) get_random_mask_addr(mac_addr, req->mac_addr, @@ -4181,10 +4898,10 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct cfg80211_scan_info info = { .aborted = aborted, }; - struct rtw89_vif *rtwvif; if (!vif) return; @@ -4197,22 +4914,29 @@ void rtw89_hw_scan_complete(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, rtw89_core_scan_complete(rtwdev, vif, true); ieee80211_scan_completed(rtwdev->hw, &info); ieee80211_wake_queues(rtwdev->hw); + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); rtw89_release_pkt_list(rtwdev); - rtwvif = (struct rtw89_vif *)vif->drv_priv; rtwvif->scan_req = NULL; rtwvif->scan_ies = NULL; scan_info->last_chan_idx = 0; scan_info->scanning_vif = NULL; + scan_info->abort = false; rtw89_chanctx_proceed(rtwdev); } void rtw89_hw_scan_abort(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) { - rtw89_hw_scan_offload(rtwdev, vif, false); - rtw89_hw_scan_complete(rtwdev, vif, true); + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + int ret; + + scan_info->abort = true; + + ret = rtw89_hw_scan_offload(rtwdev, vif, false); + if (ret) + rtw89_hw_scan_complete(rtwdev, vif, true); } static bool rtw89_is_any_vif_connected_or_connecting(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 01016588b1fc..a3df701bdc6e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -169,6 +169,16 @@ enum rtw89_scanofld_notify_reason { RTW89_SCAN_ENTER_CH_NOTIFY, RTW89_SCAN_LEAVE_CH_NOTIFY, RTW89_SCAN_END_SCAN_NOTIFY, + RTW89_SCAN_REPORT_NOTIFY, + RTW89_SCAN_CHKPT_NOTIFY, + RTW89_SCAN_ENTER_OP_NOTIFY, + RTW89_SCAN_LEAVE_OP_NOTIFY, +}; + +enum rtw89_scanofld_status { + RTW89_SCAN_STATUS_NOTIFY, + RTW89_SCAN_STATUS_SUCCESS, + RTW89_SCAN_STATUS_FAIL, }; enum rtw89_chan_type { @@ -184,6 +194,9 @@ enum rtw89_p2pps_action { RTW89_P2P_ACT_TERMINATE = 3, }; +#define RTW89_DEFAULT_CQM_HYST 4 +#define RTW89_DEFAULT_CQM_THOLD -70 + enum rtw89_bcn_fltr_offload_mode { RTW89_BCN_FLTR_OFFLOAD_MODE_0 = 0, RTW89_BCN_FLTR_OFFLOAD_MODE_1, @@ -231,6 +244,15 @@ struct rtw89_fw_macid_pause_grp { __le32 mask_grp[4]; } __packed; +struct rtw89_fw_macid_pause_sleep_grp { + struct { + __le32 pause_grp[4]; + __le32 pause_mask_grp[4]; + __le32 sleep_grp[4]; + __le32 sleep_mask_grp[4]; + } __packed n[4]; +} __packed; + #define RTW89_H2C_MAX_SIZE 2048 #define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME_6G 20 @@ -1198,6 +1220,149 @@ static inline void SET_CMC_TBL_CSI_BW(void *table, u32 val) GENMASK(31, 30)); } +struct rtw89_h2c_cctlinfo_ud_g7 { + __le32 c0; + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; + __le32 w12; + __le32 w13; + __le32 w14; + __le32 w15; + __le32 m0; + __le32 m1; + __le32 m2; + __le32 m3; + __le32 m4; + __le32 m5; + __le32 m6; + __le32 m7; + __le32 m8; + __le32 m9; + __le32 m10; + __le32 m11; + __le32 m12; + __le32 m13; + __le32 m14; + __le32 m15; +} __packed; + +#define CCTLINFO_G7_C0_MACID GENMASK(6, 0) +#define CCTLINFO_G7_C0_OP BIT(7) + +#define CCTLINFO_G7_W0_DATARATE GENMASK(11, 0) +#define CCTLINFO_G7_W0_DATA_GI_LTF GENMASK(14, 12) +#define CCTLINFO_G7_W0_TRYRATE BIT(15) +#define CCTLINFO_G7_W0_ARFR_CTRL GENMASK(17, 16) +#define CCTLINFO_G7_W0_DIS_HE1SS_STBC BIT(18) +#define CCTLINFO_G7_W0_ACQ_RPT_EN BIT(20) +#define CCTLINFO_G7_W0_MGQ_RPT_EN BIT(21) +#define CCTLINFO_G7_W0_ULQ_RPT_EN BIT(22) +#define CCTLINFO_G7_W0_TWTQ_RPT_EN BIT(23) +#define CCTLINFO_G7_W0_FORCE_TXOP BIT(24) +#define CCTLINFO_G7_W0_DISRTSFB BIT(25) +#define CCTLINFO_G7_W0_DISDATAFB BIT(26) +#define CCTLINFO_G7_W0_NSTR_EN BIT(27) +#define CCTLINFO_G7_W0_AMPDU_DENSITY GENMASK(31, 28) +#define CCTLINFO_G7_W0_ALL (GENMASK(31, 20) | GENMASK(18, 0)) +#define CCTLINFO_G7_W1_DATA_RTY_LOWEST_RATE GENMASK(11, 0) +#define CCTLINFO_G7_W1_RTS_TXCNT_LMT GENMASK(15, 12) +#define CCTLINFO_G7_W1_RTSRATE GENMASK(27, 16) +#define CCTLINFO_G7_W1_RTS_RTY_LOWEST_RATE GENMASK(31, 28) +#define CCTLINFO_G7_W1_ALL GENMASK(31, 0) +#define CCTLINFO_G7_W2_DATA_TX_CNT_LMT GENMASK(5, 0) +#define CCTLINFO_G7_W2_DATA_TXCNT_LMT_SEL BIT(6) +#define CCTLINFO_G7_W2_MAX_AGG_NUM_SEL BIT(7) +#define CCTLINFO_G7_W2_RTS_EN BIT(8) +#define CCTLINFO_G7_W2_CTS2SELF_EN BIT(9) +#define CCTLINFO_G7_W2_CCA_RTS GENMASK(11, 10) +#define CCTLINFO_G7_W2_HW_RTS_EN BIT(12) +#define CCTLINFO_G7_W2_RTS_DROP_DATA_MODE GENMASK(14, 13) +#define CCTLINFO_G7_W2_PRELD_EN BIT(15) +#define CCTLINFO_G7_W2_AMPDU_MAX_LEN GENMASK(26, 16) +#define CCTLINFO_G7_W2_UL_MU_DIS BIT(27) +#define CCTLINFO_G7_W2_AMPDU_MAX_TIME GENMASK(31, 28) +#define CCTLINFO_G7_W2_ALL GENMASK(31, 0) +#define CCTLINFO_G7_W3_MAX_AGG_NUM GENMASK(7, 0) +#define CCTLINFO_G7_W3_DATA_BW GENMASK(10, 8) +#define CCTLINFO_G7_W3_DATA_BW_ER BIT(11) +#define CCTLINFO_G7_W3_BA_BMAP GENMASK(14, 12) +#define CCTLINFO_G7_W3_VCS_STBC BIT(15) +#define CCTLINFO_G7_W3_VO_LFTIME_SEL GENMASK(18, 16) +#define CCTLINFO_G7_W3_VI_LFTIME_SEL GENMASK(21, 19) +#define CCTLINFO_G7_W3_BE_LFTIME_SEL GENMASK(24, 22) +#define CCTLINFO_G7_W3_BK_LFTIME_SEL GENMASK(27, 25) +#define CCTLINFO_G7_W3_AMPDU_TIME_SEL BIT(28) +#define CCTLINFO_G7_W3_AMPDU_LEN_SEL BIT(29) +#define CCTLINFO_G7_W3_RTS_TXCNT_LMT_SEL BIT(30) +#define CCTLINFO_G7_W3_LSIG_TXOP_EN BIT(31) +#define CCTLINFO_G7_W3_ALL GENMASK(31, 0) +#define CCTLINFO_G7_W4_MULTI_PORT_ID GENMASK(2, 0) +#define CCTLINFO_G7_W4_BYPASS_PUNC BIT(3) +#define CCTLINFO_G7_W4_MBSSID GENMASK(7, 4) +#define CCTLINFO_G7_W4_DATA_DCM BIT(8) +#define CCTLINFO_G7_W4_DATA_ER BIT(9) +#define CCTLINFO_G7_W4_DATA_LDPC BIT(10) +#define CCTLINFO_G7_W4_DATA_STBC BIT(11) +#define CCTLINFO_G7_W4_A_CTRL_BQR BIT(12) +#define CCTLINFO_G7_W4_A_CTRL_BSR BIT(14) +#define CCTLINFO_G7_W4_A_CTRL_CAS BIT(15) +#define CCTLINFO_G7_W4_ACT_SUBCH_CBW GENMASK(31, 16) +#define CCTLINFO_G7_W4_ALL (GENMASK(31, 14) | GENMASK(12, 0)) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING0 GENMASK(1, 0) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING1 GENMASK(3, 2) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING2 GENMASK(5, 4) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING3 GENMASK(7, 6) +#define CCTLINFO_G7_W5_NOMINAL_PKT_PADDING4 GENMASK(9, 8) +#define CCTLINFO_G7_W5_SR_RATE GENMASK(14, 10) +#define CCTLINFO_G7_W5_TID_DISABLE GENMASK(23, 16) +#define CCTLINFO_G7_W5_ADDR_CAM_INDEX GENMASK(31, 24) +#define CCTLINFO_G7_W5_ALL (GENMASK(31, 16) | GENMASK(14, 0)) +#define CCTLINFO_G7_W6_AID12_PAID GENMASK(11, 0) +#define CCTLINFO_G7_W6_RESP_REF_RATE GENMASK(23, 12) +#define CCTLINFO_G7_W6_ULDL BIT(31) +#define CCTLINFO_G7_W6_ALL (BIT(31) | GENMASK(23, 0)) +#define CCTLINFO_G7_W7_NC GENMASK(2, 0) +#define CCTLINFO_G7_W7_NR GENMASK(5, 3) +#define CCTLINFO_G7_W7_NG GENMASK(7, 6) +#define CCTLINFO_G7_W7_CB GENMASK(9, 8) +#define CCTLINFO_G7_W7_CS GENMASK(11, 10) +#define CCTLINFO_G7_W7_CSI_STBC_EN BIT(13) +#define CCTLINFO_G7_W7_CSI_LDPC_EN BIT(14) +#define CCTLINFO_G7_W7_CSI_PARA_EN BIT(15) +#define CCTLINFO_G7_W7_CSI_FIX_RATE GENMASK(27, 16) +#define CCTLINFO_G7_W7_CSI_BW GENMASK(31, 29) +#define CCTLINFO_G7_W7_ALL (GENMASK(31, 29) | GENMASK(27, 13) | GENMASK(11, 0)) +#define CCTLINFO_G7_W8_ALL_ACK_SUPPORT BIT(0) +#define CCTLINFO_G7_W8_BSR_QUEUE_SIZE_FORMAT BIT(1) +#define CCTLINFO_G7_W8_BSR_OM_UPD_EN BIT(2) +#define CCTLINFO_G7_W8_MACID_FWD_IDC BIT(3) +#define CCTLINFO_G7_W8_AZ_SEC_EN BIT(4) +#define CCTLINFO_G7_W8_CSI_SEC_EN BIT(5) +#define CCTLINFO_G7_W8_FIX_UL_ADDRCAM_IDX BIT(6) +#define CCTLINFO_G7_W8_CTRL_CNT_VLD BIT(7) +#define CCTLINFO_G7_W8_CTRL_CNT GENMASK(11, 8) +#define CCTLINFO_G7_W8_RESP_SEC_TYPE GENMASK(15, 12) +#define CCTLINFO_G7_W8_ALL GENMASK(15, 0) +/* W9~13 are reserved */ +#define CCTLINFO_G7_W14_VO_CURR_RATE GENMASK(11, 0) +#define CCTLINFO_G7_W14_VI_CURR_RATE GENMASK(23, 12) +#define CCTLINFO_G7_W14_BE_CURR_RATE_L GENMASK(31, 24) +#define CCTLINFO_G7_W14_ALL GENMASK(31, 0) +#define CCTLINFO_G7_W15_BE_CURR_RATE_H GENMASK(3, 0) +#define CCTLINFO_G7_W15_BK_CURR_RATE GENMASK(15, 4) +#define CCTLINFO_G7_W15_MGNT_CURR_RATE GENMASK(27, 16) +#define CCTLINFO_G7_W15_ALL GENMASK(27, 0) + static inline void SET_DCTL_MACID_V1(void *table, u32 val) { le32p_replace_bits((__le32 *)(table) + 0, val, GENMASK(6, 0)); @@ -1500,105 +1665,80 @@ static inline void SET_DCTL_SEC_ENT6_V1(void *table, u32 val) GENMASK(31, 24)); } -static inline void SET_BCN_UPD_PORT(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); -} - -static inline void SET_BCN_UPD_MBSSID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); -} - -static inline void SET_BCN_UPD_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 16)); -} - -static inline void SET_BCN_UPD_GRP_IE_OFST(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, (val - 24) | BIT(7), GENMASK(31, 24)); -} - -static inline void SET_BCN_UPD_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(7, 0)); -} - -static inline void SET_BCN_UPD_SSN_SEL(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(9, 8)); -} - -static inline void SET_BCN_UPD_SSN_MODE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(11, 10)); -} - -static inline void SET_BCN_UPD_RATE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(20, 12)); -} - -static inline void SET_BCN_UPD_TXPWR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 1, val, GENMASK(23, 21)); -} - -static inline void SET_BCN_UPD_TXINFO_CTRL_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(0)); -} - -static inline void SET_BCN_UPD_NTX_PATH_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(4, 1)); -} - -static inline void SET_BCN_UPD_PATH_MAP_A(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(6, 5)); -} - -static inline void SET_BCN_UPD_PATH_MAP_B(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(8, 7)); -} - -static inline void SET_BCN_UPD_PATH_MAP_C(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(10, 9)); -} - -static inline void SET_BCN_UPD_PATH_MAP_D(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(12, 11)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_A(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(13)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_B(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(14)); -} - -static inline void SET_BCN_UPD_PATH_ANTSEL_C(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(15)); -} +struct rtw89_h2c_bcn_upd { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; -static inline void SET_BCN_UPD_PATH_ANTSEL_D(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, BIT(16)); -} +#define RTW89_H2C_BCN_UPD_W0_PORT GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_W0_MBSSID GENMASK(15, 8) +#define RTW89_H2C_BCN_UPD_W0_BAND GENMASK(23, 16) +#define RTW89_H2C_BCN_UPD_W0_GRP_IE_OFST GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_W1_MACID GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_W1_SSN_SEL GENMASK(9, 8) +#define RTW89_H2C_BCN_UPD_W1_SSN_MODE GENMASK(11, 10) +#define RTW89_H2C_BCN_UPD_W1_RATE GENMASK(20, 12) +#define RTW89_H2C_BCN_UPD_W1_TXPWR GENMASK(23, 21) +#define RTW89_H2C_BCN_UPD_W2_TXINFO_CTRL_EN BIT(0) +#define RTW89_H2C_BCN_UPD_W2_NTX_PATH_EN GENMASK(4, 1) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_A GENMASK(6, 5) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_B GENMASK(8, 7) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_C GENMASK(10, 9) +#define RTW89_H2C_BCN_UPD_W2_PATH_MAP_D GENMASK(12, 11) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_A BIT(13) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_B BIT(14) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_C BIT(15) +#define RTW89_H2C_BCN_UPD_W2_PATH_ANTSEL_D BIT(16) +#define RTW89_H2C_BCN_UPD_W2_CSA_OFST GENMASK(31, 17) + +struct rtw89_h2c_bcn_upd_be { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; + __le32 w8; + __le32 w9; + __le32 w10; + __le32 w11; +} __packed; -static inline void SET_BCN_UPD_CSA_OFST(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 17)); -} +#define RTW89_H2C_BCN_UPD_BE_W0_PORT GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_BE_W0_MBSSID GENMASK(15, 8) +#define RTW89_H2C_BCN_UPD_BE_W0_BAND GENMASK(23, 16) +#define RTW89_H2C_BCN_UPD_BE_W0_GRP_IE_OFST GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_BE_W1_MACID GENMASK(7, 0) +#define RTW89_H2C_BCN_UPD_BE_W1_SSN_SEL GENMASK(9, 8) +#define RTW89_H2C_BCN_UPD_BE_W1_SSN_MODE GENMASK(11, 10) +#define RTW89_H2C_BCN_UPD_BE_W1_RATE GENMASK(20, 12) +#define RTW89_H2C_BCN_UPD_BE_W1_TXPWR GENMASK(23, 21) +#define RTW89_H2C_BCN_UPD_BE_W1_MACID_EXT GENMASK(31, 24) +#define RTW89_H2C_BCN_UPD_BE_W2_TXINFO_CTRL_EN BIT(0) +#define RTW89_H2C_BCN_UPD_BE_W2_NTX_PATH_EN GENMASK(4, 1) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_A GENMASK(6, 5) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_B GENMASK(8, 7) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_C GENMASK(10, 9) +#define RTW89_H2C_BCN_UPD_BE_W2_PATH_MAP_D GENMASK(12, 11) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_A BIT(13) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_B BIT(14) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_C BIT(15) +#define RTW89_H2C_BCN_UPD_BE_W2_ANTSEL_D BIT(16) +#define RTW89_H2C_BCN_UPD_BE_W2_CSA_OFST GENMASK(31, 17) +#define RTW89_H2C_BCN_UPD_BE_W3_MLIE_CSA_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W3_CRITICAL_UPD_FLAG_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W4_VAP1_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W4_VAP2_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W5_VAP3_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W5_VAP4_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W6_VAP5_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W6_VAP6_DTIM_CNT_OFST GENMASK(31, 16) +#define RTW89_H2C_BCN_UPD_BE_W7_VAP7_DTIM_CNT_OFST GENMASK(15, 0) +#define RTW89_H2C_BCN_UPD_BE_W7_ECSA_OFST GENMASK(30, 16) +#define RTW89_H2C_BCN_UPD_BE_W7_PROTECTION_KEY_ID BIT(31) static inline void SET_FWROLE_MAINTAIN_MACID(void *h2c, u32 val) { @@ -1620,70 +1760,46 @@ static inline void SET_FWROLE_MAINTAIN_WIFI_ROLE(void *h2c, u32 val) le32p_replace_bits((__le32 *)h2c, val, GENMASK(16, 13)); } -static inline void SET_JOININFO_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 0)); -} - -static inline void SET_JOININFO_OP(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(8)); -} - -static inline void SET_JOININFO_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(9)); -} - -static inline void SET_JOININFO_WMM(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(11, 10)); -} - -static inline void SET_JOININFO_TGR(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(12)); -} - -static inline void SET_JOININFO_ISHESTA(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(13)); -} - -static inline void SET_JOININFO_DLBW(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 14)); -} - -static inline void SET_JOININFO_TF_MAC_PAD(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(17, 16)); -} - -static inline void SET_JOININFO_DL_T_PE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(20, 18)); -} - -static inline void SET_JOININFO_PORT_ID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(23, 21)); -} +enum rtw89_fw_sta_type { /* value of RTW89_H2C_JOININFO_W1_STA_TYPE */ + RTW89_FW_N_AC_STA = 0, + RTW89_FW_AX_STA = 1, + RTW89_FW_BE_STA = 2, +}; -static inline void SET_JOININFO_NET_TYPE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(25, 24)); -} +struct rtw89_h2c_join { + __le32 w0; +} __packed; -static inline void SET_JOININFO_WIFI_ROLE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(29, 26)); -} +struct rtw89_h2c_join_v1 { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; -static inline void SET_JOININFO_SELF_ROLE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 30)); -} +#define RTW89_H2C_JOININFO_W0_MACID GENMASK(7, 0) +#define RTW89_H2C_JOININFO_W0_OP BIT(8) +#define RTW89_H2C_JOININFO_W0_BAND BIT(9) +#define RTW89_H2C_JOININFO_W0_WMM GENMASK(11, 10) +#define RTW89_H2C_JOININFO_W0_TGR BIT(12) +#define RTW89_H2C_JOININFO_W0_ISHESTA BIT(13) +#define RTW89_H2C_JOININFO_W0_DLBW GENMASK(15, 14) +#define RTW89_H2C_JOININFO_W0_TF_MAC_PAD GENMASK(17, 16) +#define RTW89_H2C_JOININFO_W0_DL_T_PE GENMASK(20, 18) +#define RTW89_H2C_JOININFO_W0_PORT_ID GENMASK(23, 21) +#define RTW89_H2C_JOININFO_W0_NET_TYPE GENMASK(25, 24) +#define RTW89_H2C_JOININFO_W0_WIFI_ROLE GENMASK(29, 26) +#define RTW89_H2C_JOININFO_W0_SELF_ROLE GENMASK(31, 30) +#define RTW89_H2C_JOININFO_W1_STA_TYPE GENMASK(2, 0) +#define RTW89_H2C_JOININFO_W1_IS_MLD BIT(3) +#define RTW89_H2C_JOININFO_W1_MAIN_MACID GENMASK(11, 4) +#define RTW89_H2C_JOININFO_W1_MLO_MODE BIT(12) +#define RTW89_H2C_JOININFO_W1_EMLSR_CAB BIT(13) +#define RTW89_H2C_JOININFO_W1_NSTR_EN BIT(14) +#define RTW89_H2C_JOININFO_W1_INIT_PWR_STATE BIT(15) +#define RTW89_H2C_JOININFO_W1_EMLSR_PADDING GENMASK(18, 16) +#define RTW89_H2C_JOININFO_W1_EMLSR_TRANS_DELAY GENMASK(21, 19) +#define RTW89_H2C_JOININFO_W2_MACID_EXT GENMASK(7, 0) +#define RTW89_H2C_JOININFO_W2_MAIN_MACID_EXT GENMASK(15, 8) struct rtw89_h2c_notify_dbcc { __le32 w0; @@ -1741,60 +1857,47 @@ static inline void SET_LOG_CFG_COMP_EXT(void *h2c, u32 val) le32p_replace_bits((__le32 *)(h2c) + 2, val, GENMASK(31, 0)); } -static inline void SET_BA_CAM_VALID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(0)); -} - -static inline void SET_BA_CAM_INIT_REQ(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, BIT(1)); -} - -static inline void SET_BA_CAM_ENTRY_IDX(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(3, 2)); -} - -static inline void SET_BA_CAM_TID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(7, 4)); -} - -static inline void SET_BA_CAM_MACID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(15, 8)); -} - -static inline void SET_BA_CAM_BMAP_SIZE(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(19, 16)); -} - -static inline void SET_BA_CAM_SSN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c, val, GENMASK(31, 20)); -} - -static inline void SET_BA_CAM_UID(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(7, 0)); -} +struct rtw89_h2c_ba_cam { + __le32 w0; + __le32 w1; +} __packed; -static inline void SET_BA_CAM_STD_EN(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, BIT(8)); -} +#define RTW89_H2C_BA_CAM_W0_VALID BIT(0) +#define RTW89_H2C_BA_CAM_W0_INIT_REQ BIT(1) +#define RTW89_H2C_BA_CAM_W0_ENTRY_IDX GENMASK(3, 2) +#define RTW89_H2C_BA_CAM_W0_TID GENMASK(7, 4) +#define RTW89_H2C_BA_CAM_W0_MACID GENMASK(15, 8) +#define RTW89_H2C_BA_CAM_W0_BMAP_SIZE GENMASK(19, 16) +#define RTW89_H2C_BA_CAM_W0_SSN GENMASK(31, 20) +#define RTW89_H2C_BA_CAM_W1_UID GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_W1_STD_EN BIT(8) +#define RTW89_H2C_BA_CAM_W1_BAND BIT(9) +#define RTW89_H2C_BA_CAM_W1_ENTRY_IDX_V1 GENMASK(31, 28) + +struct rtw89_h2c_ba_cam_v1 { + __le32 w0; + __le32 w1; +} __packed; -static inline void SET_BA_CAM_BAND(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, BIT(9)); -} +#define RTW89_H2C_BA_CAM_V1_W0_VALID BIT(0) +#define RTW89_H2C_BA_CAM_V1_W0_INIT_REQ BIT(1) +#define RTW89_H2C_BA_CAM_V1_W0_TID_MASK GENMASK(7, 4) +#define RTW89_H2C_BA_CAM_V1_W0_MACID_MASK GENMASK(15, 8) +#define RTW89_H2C_BA_CAM_V1_W0_BMAP_SIZE_MASK GENMASK(19, 16) +#define RTW89_H2C_BA_CAM_V1_W0_SSN_MASK GENMASK(31, 20) +#define RTW89_H2C_BA_CAM_V1_W1_UID_VALUE_MASK GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_V1_W1_STD_ENTRY_EN BIT(8) +#define RTW89_H2C_BA_CAM_V1_W1_BAND_SEL BIT(9) +#define RTW89_H2C_BA_CAM_V1_W1_MLD_EN BIT(10) +#define RTW89_H2C_BA_CAM_V1_W1_ENTRY_IDX_MASK GENMASK(31, 24) + +struct rtw89_h2c_ba_cam_init { + __le32 w0; +} __packed; -static inline void SET_BA_CAM_ENTRY_IDX_V1(void *h2c, u32 val) -{ - le32p_replace_bits((__le32 *)h2c + 1, val, GENMASK(31, 28)); -} +#define RTW89_H2C_BA_CAM_INIT_USERS_MASK GENMASK(7, 0) +#define RTW89_H2C_BA_CAM_INIT_OFFSET_MASK GENMASK(19, 12) +#define RTW89_H2C_BA_CAM_INIT_BAND_SEL BIT(24) static inline void SET_LPS_PARM_MACID(void *h2c, u32 val) { @@ -2569,135 +2672,48 @@ static inline void RTW89_SET_FWCMD_PACKET_OFLD_PKT_LENGTH(void *cmd, u32 val) le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 16)); } -static inline void RTW89_SET_FWCMD_SCANOFLD_CH_NUM(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_SCANOFLD_CH_SIZE(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PERIOD(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_DWELL(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_CENTER_CH(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PRI_CH(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd)), val, GENMASK(31, 24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_BW(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(2, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_ACTION(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(7, 3)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_NUM_PKT(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(11, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_TX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(12)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PAUSE_DATA(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(13)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_BAND(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(15, 14)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT_ID(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_DFS(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_TX_NULL(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(25)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_RANDOM(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(26)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_CFG_TX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 4), val, BIT(27)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT0(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT1(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT2(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT3(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 8), val, GENMASK(31, 24)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT4(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(7, 0)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT5(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(15, 8)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT6(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(23, 16)); -} - -static inline void RTW89_SET_FWCMD_CHINFO_PKT7(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 12), val, GENMASK(31, 24)); -} +struct rtw89_h2c_chinfo_elem { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; +} __packed; -static inline void RTW89_SET_FWCMD_CHINFO_POWER_IDX(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)((u8 *)(cmd) + 16), val, GENMASK(15, 0)); -} +#define RTW89_H2C_CHINFO_W0_PERIOD GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W0_DWELL GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W0_PRI_CH GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W1_BW GENMASK(2, 0) +#define RTW89_H2C_CHINFO_W1_ACTION GENMASK(7, 3) +#define RTW89_H2C_CHINFO_W1_NUM_PKT GENMASK(11, 8) +#define RTW89_H2C_CHINFO_W1_TX BIT(12) +#define RTW89_H2C_CHINFO_W1_PAUSE_DATA BIT(13) +#define RTW89_H2C_CHINFO_W1_BAND GENMASK(15, 14) +#define RTW89_H2C_CHINFO_W1_PKT_ID GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W1_DFS BIT(24) +#define RTW89_H2C_CHINFO_W1_TX_NULL BIT(25) +#define RTW89_H2C_CHINFO_W1_RANDOM BIT(26) +#define RTW89_H2C_CHINFO_W1_CFG_TX BIT(27) +#define RTW89_H2C_CHINFO_W2_PKT0 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W2_PKT1 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W2_PKT2 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W2_PKT3 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W3_PKT4 GENMASK(7, 0) +#define RTW89_H2C_CHINFO_W3_PKT5 GENMASK(15, 8) +#define RTW89_H2C_CHINFO_W3_PKT6 GENMASK(23, 16) +#define RTW89_H2C_CHINFO_W3_PKT7 GENMASK(31, 24) +#define RTW89_H2C_CHINFO_W4_POWER_IDX GENMASK(15, 0) + +struct rtw89_h2c_chinfo { + u8 ch_num; + u8 elem_size; + u8 rsvd0; + u8 rsvd1; + struct rtw89_h2c_chinfo_elem elem[] __counted_by(ch_num); +} __packed; struct rtw89_h2c_scanofld { __le32 w0; @@ -3275,20 +3291,24 @@ struct rtw89_c2h_ra_rpt { #define RTW89_GET_MAC_C2H_PKTOFLD_LEN(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 16)) -#define RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(7, 0)) -#define RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(19, 16)) -#define RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(23, 20)) -#define RTW89_GET_MAC_C2H_ACTUAL_PERIOD(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(31, 24)) -#define RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(3, 0)) -#define RTW89_GET_MAC_C2H_SCANOFLD_AIR_DENSITY(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(7, 4)) -#define RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h) \ - le32_get_bits(*((const __le32 *)(c2h) + 5), GENMASK(25, 24)) +struct rtw89_c2h_scanofld { + __le32 w0; + __le32 w1; + __le32 w2; + __le32 w3; + __le32 w4; + __le32 w5; + __le32 w6; + __le32 w7; +} __packed; + +#define RTW89_C2H_SCANOFLD_W2_PRI_CH GENMASK(7, 0) +#define RTW89_C2H_SCANOFLD_W2_RSN GENMASK(19, 16) +#define RTW89_C2H_SCANOFLD_W2_STATUS GENMASK(23, 20) +#define RTW89_C2H_SCANOFLD_W2_PERIOD GENMASK(31, 24) +#define RTW89_C2H_SCANOFLD_W5_TX_FAIL GENMASK(3, 0) +#define RTW89_C2H_SCANOFLD_W5_AIR_DENSITY GENMASK(7, 4) +#define RTW89_C2H_SCANOFLD_W5_BAND GENMASK(25, 24) #define RTW89_GET_MAC_C2H_MCC_RCV_ACK_GROUP(c2h) \ le32_get_bits(*((const __le32 *)(c2h) + 2), GENMASK(1, 0)) @@ -3647,6 +3667,9 @@ struct rtw89_fw_h2c_rf_reg_info { #define H2C_FUNC_MAC_BCN_UPD 0x5 #define H2C_FUNC_MAC_DCTLINFO_UD_V1 0x9 #define H2C_FUNC_MAC_CCTLINFO_UD_V1 0xa +#define H2C_FUNC_MAC_DCTLINFO_UD_V2 0xc +#define H2C_FUNC_MAC_BCN_UPD_BE 0xd +#define H2C_FUNC_MAC_CCTLINFO_UD_G7 0x11 /* CLASS 6 - Address CAM */ #define H2C_CL_MAC_ADDR_CAM_UPDATE 0x6 @@ -3672,6 +3695,7 @@ enum rtw89_fw_ofld_h2c_func { H2C_FUNC_CFG_BCNFLTR = 0x1e, H2C_FUNC_OFLD_RSSI = 0x1f, H2C_FUNC_OFLD_TP = 0x20, + H2C_FUNC_MAC_MACID_PAUSE_SLEEP = 0x28, NUM_OF_RTW89_FW_OFLD_H2C_FUNC, }; @@ -3683,6 +3707,11 @@ enum rtw89_fw_ofld_h2c_func { RTW89_FW_OFLD_WAIT_COND(RTW89_PKT_OFLD_WAIT_TAG(pkt_id, pkt_op), \ H2C_FUNC_PACKET_OFLD) +#define RTW89_SCANOFLD_WAIT_COND_ADD_CH RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_ADD_SCANOFLD_CH) + +#define RTW89_SCANOFLD_WAIT_COND_START RTW89_FW_OFLD_WAIT_COND(0, H2C_FUNC_SCANOFLD) +#define RTW89_SCANOFLD_WAIT_COND_STOP RTW89_FW_OFLD_WAIT_COND(1, H2C_FUNC_SCANOFLD) + /* CLASS 10 - Security CAM */ #define H2C_CL_MAC_SEC_CAM 0xa #define H2C_FUNC_MAC_SEC_UPD 0x1 @@ -3690,6 +3719,8 @@ enum rtw89_fw_ofld_h2c_func { /* CLASS 12 - BA CAM */ #define H2C_CL_BA_CAM 0xc #define H2C_FUNC_MAC_BA_CAM 0x0 +#define H2C_FUNC_MAC_BA_CAM_V1 0x1 +#define H2C_FUNC_MAC_BA_CAM_INIT 0x2 /* CLASS 14 - MCC */ #define H2C_CL_MCC 0xe @@ -3830,21 +3861,39 @@ void rtw89_h2c_pkt_set_hdr(struct rtw89_dev *rtwdev, struct sk_buff *skb, u8 type, u8 cat, u8 class, u8 func, bool rack, bool dack, u32 len); int rtw89_fw_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif); + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_default_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_default_dmac_tbl_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); int rtw89_fw_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta); +int rtw89_fw_h2c_assoc_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int rtw89_fw_h2c_ampdu_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); +int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif); int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif *vif, struct rtw89_sta *rtwsta, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, struct rtw89_sta *rtwsta); +int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct work_struct *work); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, @@ -3876,7 +3925,7 @@ int rtw89_fw_h2c_cxdrv_rfk(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_del_pkt_offload(struct rtw89_dev *rtwdev, u8 id); int rtw89_fw_h2c_add_pkt_offload(struct rtw89_dev *rtwdev, u8 *id, struct sk_buff *skb_ofld); -int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int len, +int rtw89_fw_h2c_scan_list_offload(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list); int rtw89_fw_h2c_scan_offload(struct rtw89_dev *rtwdev, struct rtw89_scan_option *opt, @@ -3898,7 +3947,11 @@ void rtw89_fw_release_general_pkt_list_vif(struct rtw89_dev *rtwdev, void rtw89_fw_release_general_pkt_list(struct rtw89_dev *rtwdev, bool notify_fw); int rtw89_fw_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params); +int rtw89_fw_h2c_ba_cam_v1(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params); void rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_init_ba_cam_users(struct rtw89_dev *rtwdev, u8 users, + u8 offset, u8 mac_idx); int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param); @@ -3965,6 +4018,65 @@ static inline void rtw89_fw_h2c_init_ba_cam(struct rtw89_dev *rtwdev) rtw89_fw_h2c_init_dynamic_ba_cam_v0_ext(rtwdev); } +static inline int rtw89_chip_h2c_default_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_default_cmac_tbl(rtwdev, rtwvif, rtwsta); +} + +static inline int rtw89_chip_h2c_default_dmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, + struct rtw89_sta *rtwsta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->h2c_default_dmac_tbl) + return chip->ops->h2c_default_dmac_tbl(rtwdev, rtwvif, rtwsta); + + return 0; +} + +static inline int rtw89_chip_h2c_update_beacon(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_update_beacon(rtwdev, rtwvif); +} + +static inline int rtw89_chip_h2c_assoc_cmac_tbl(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_assoc_cmac_tbl(rtwdev, vif, sta); +} + +static inline int rtw89_chip_h2c_ampdu_cmac_tbl(struct rtw89_dev *rtwdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (chip->ops->h2c_ampdu_cmac_tbl) + return chip->ops->h2c_ampdu_cmac_tbl(rtwdev, vif, sta); + + return 0; +} + +static inline +int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, + bool valid, struct ieee80211_ampdu_params *params) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->h2c_ba_cam(rtwdev, rtwsta, valid, params); +} + /* must consider compatibility; don't insert new in the mid */ struct rtw89_fw_txpwr_byrate_entry { u8 band; diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index c485ef2cc3d3..eb94e832e154 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -3676,6 +3676,28 @@ static int trx_init_ax(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mac_feat_init(struct rtw89_dev *rtwdev) +{ +#define BACAM_1024BMP_OCC_ENTRY 4 +#define BACAM_MAX_RU_SUPPORT_B0_STA 1 +#define BACAM_MAX_RU_SUPPORT_B1_STA 1 + const struct rtw89_chip_info *chip = rtwdev->chip; + u8 users, offset; + + if (chip->bacam_ver != RTW89_BACAM_V1) + return 0; + + offset = 0; + users = BACAM_MAX_RU_SUPPORT_B0_STA; + rtw89_fw_h2c_init_ba_cam_users(rtwdev, users, offset, RTW89_MAC_0); + + offset += users * BACAM_1024BMP_OCC_ENTRY; + users = BACAM_MAX_RU_SUPPORT_B1_STA; + rtw89_fw_h2c_init_ba_cam_users(rtwdev, users, offset, RTW89_MAC_1); + + return 0; +} + static void rtw89_disable_fw_watchdog(struct rtw89_dev *rtwdev) { enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; @@ -3910,6 +3932,10 @@ int rtw89_mac_init(struct rtw89_dev *rtwdev) if (ret) goto fail; + ret = rtw89_mac_feat_init(rtwdev); + if (ret) + goto fail; + if (rtwdev->hci.ops->mac_post_init) { ret = rtwdev->hci.ops->mac_post_init(rtwdev); if (ret) @@ -4046,7 +4072,7 @@ static void rtw89_mac_bcn_drop(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvi rtw89_write32_clr(rtwdev, R_AX_BCN_DROP_ALL0, BIT(rtwvif->port)); rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TBTT_PROHIB_EN); - fsleep(2); + fsleep(2000); } #define BCN_INTERVAL 100 @@ -4159,13 +4185,11 @@ static void rtw89_mac_port_cfg_rx_sw(struct rtw89_dev *rtwdev, rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, bit); } -static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, - struct rtw89_vif *rtwvif) +void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || - rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; if (en) rtw89_write32_port_set(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); @@ -4173,6 +4197,15 @@ static void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, rtw89_write32_port_clr(rtwdev, rtwvif, p->port_cfg, B_AX_TSF_UDT_EN); } +static void rtw89_mac_port_cfg_rx_sync_by_nettype(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif) +{ + bool en = rtwvif->net_type == RTW89_NET_TYPE_INFRA || + rtwvif->net_type == RTW89_NET_TYPE_AD_HOC; + + rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif, en); +} + static void rtw89_mac_port_cfg_tx_sw(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, bool en) { @@ -4471,7 +4504,11 @@ int rtw89_mac_vif_init(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) if (ret) return ret; - ret = rtw89_fw_h2c_default_cmac_tbl(rtwdev, rtwvif); + ret = rtw89_chip_h2c_default_cmac_tbl(rtwdev, rtwvif, NULL); + if (ret) + return ret; + + ret = rtw89_chip_h2c_default_dmac_tbl(rtwdev, rtwvif, NULL); if (ret) return ret; @@ -4508,7 +4545,7 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) rtw89_mac_port_cfg_net_type(rtwdev, rtwvif); rtw89_mac_port_cfg_bcn_prct(rtwdev, rtwvif); rtw89_mac_port_cfg_rx_sw(rtwdev, rtwvif); - rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif); + rtw89_mac_port_cfg_rx_sync_by_nettype(rtwdev, rtwvif); rtw89_mac_port_cfg_tx_sw_by_nettype(rtwdev, rtwvif); rtw89_mac_port_cfg_bcn_intv(rtwdev, rtwvif); rtw89_mac_port_cfg_hiq_win(rtwdev, rtwvif); @@ -4641,9 +4678,11 @@ static bool rtw89_is_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) } static void -rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, +rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len) { + const struct rtw89_c2h_scanofld *c2h = + (const struct rtw89_c2h_scanofld *)skb->data; struct ieee80211_vif *vif = rtwdev->scan_info.scanning_vif; struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); struct rtw89_chan new; @@ -4655,12 +4694,12 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, if (!rtwvif) return; - tx_fail = RTW89_GET_MAC_C2H_SCANOFLD_TX_FAIL(c2h->data); - status = RTW89_GET_MAC_C2H_SCANOFLD_STATUS(c2h->data); - chan = RTW89_GET_MAC_C2H_SCANOFLD_PRI_CH(c2h->data); - reason = RTW89_GET_MAC_C2H_SCANOFLD_RSP(c2h->data); - band = RTW89_GET_MAC_C2H_SCANOFLD_BAND(c2h->data); - actual_period = RTW89_GET_MAC_C2H_ACTUAL_PERIOD(c2h->data); + tx_fail = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_TX_FAIL); + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); + chan = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PRI_CH); + reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); + band = le32_get_bits(c2h->w5, RTW89_C2H_SCANOFLD_W5_BAND); + actual_period = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_PERIOD); if (!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ))) band = chan > 14 ? RTW89_BAND_5G : RTW89_BAND_2G; @@ -4685,7 +4724,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *c2h, rtw89_warn(rtwdev, "HW scan failed: %d\n", ret); } } else { - rtw89_hw_scan_complete(rtwdev, vif, false); + rtw89_hw_scan_complete(rtwdev, vif, rtwdev->scan_info.abort); } break; case RTW89_SCAN_ENTER_CH_NOTIFY: @@ -4807,8 +4846,10 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le default: return; case H2C_FUNC_ADD_SCANOFLD_CH: + cond = RTW89_SCANOFLD_WAIT_COND_ADD_CH; + break; case H2C_FUNC_SCANOFLD: - cond = RTW89_FW_OFLD_WAIT_COND(0, h2c_func); + cond = RTW89_SCANOFLD_WAIT_COND_START; break; } @@ -5052,7 +5093,25 @@ void (* const rtw89_mac_c2h_mcc_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_MCC_STATUS_RPT] = rtw89_mac_c2h_mcc_status_rpt, }; -bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) +static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, + struct sk_buff *skb) +{ + const struct rtw89_c2h_scanofld *c2h = + (const struct rtw89_c2h_scanofld *)skb->data; + struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_completion_data data = {}; + u8 status, reason; + + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); + reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); + data.err = status != RTW89_SCAN_STATUS_SUCCESS; + + if (reason == RTW89_SCAN_END_SCAN_NOTIFY) + rtw89_complete_cond(fw_ofld_wait, RTW89_SCANOFLD_WAIT_COND_STOP, &data); +} + +bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, + u8 class, u8 func) { switch (class) { default: @@ -5069,6 +5128,9 @@ bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) switch (func) { default: return false; + case RTW89_MAC_C2H_FUNC_SCANOFLD_RSP: + rtw89_mac_c2h_scanofld_rsp_atomic(rtwdev, c2h); + return false; case RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP: return true; } diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index ed98b49809a4..181d03d1f78a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -1086,6 +1086,8 @@ void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, u16 offset_tu); int rtw89_mac_port_get_tsf(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, u64 *tsf); +void rtw89_mac_port_cfg_rx_sync(struct rtw89_dev *rtwdev, + struct rtw89_vif *rtwvif, bool en); void rtw89_mac_set_he_obss_narrow_bw_ru(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif); void rtw89_mac_stop_ap(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); @@ -1127,7 +1129,8 @@ static inline int rtw89_chip_reset_bb_rf(struct rtw89_dev *rtwdev) u32 rtw89_mac_get_err_status(struct rtw89_dev *rtwdev); int rtw89_mac_set_err_status(struct rtw89_dev *rtwdev, u32 err); -bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func); +bool rtw89_mac_c2h_chk_atomic(struct rtw89_dev *rtwdev, struct sk_buff *c2h, + u8 class, u8 func); void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, u32 len, u8 class, u8 func); int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index 93889d2fface..b61c5be8cae3 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -441,7 +441,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, * when disconnected by peer */ if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); } } @@ -452,7 +452,7 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_BEACON) - rtw89_fw_h2c_update_beacon(rtwdev, rtwvif); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); if (changed & BSS_CHANGED_ERP_SLOT) rtw89_conf_tx(rtwdev, rtwvif); @@ -497,7 +497,7 @@ static int rtw89_ops_start_ap(struct ieee80211_hw *hw, ether_addr_copy(rtwvif->bssid, vif->bss_conf.bssid); rtw89_cam_bssid_changed(rtwdev, rtwvif); rtw89_mac_port_update(rtwdev, rtwvif); - rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, RTW89_ROLE_TYPE_CHANGE); rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); rtw89_fw_h2c_cam(rtwdev, rtwvif, NULL, NULL); @@ -518,7 +518,7 @@ void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&rtwdev->mutex); rtw89_mac_stop_ap(rtwdev, rtwvif); - rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); + rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, true); mutex_unlock(&rtwdev->mutex); } @@ -660,6 +660,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mutex_lock(&rtwdev->mutex); clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); + clear_bit(tid, rtwsta->ampdu_map); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); mutex_unlock(&rtwdev->mutex); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; @@ -668,17 +670,19 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); rtwsta->ampdu_params[tid].agg_num = params->buf_size; rtwsta->ampdu_params[tid].amsdu = params->amsdu; + set_bit(tid, rtwsta->ampdu_map); rtw89_leave_ps_mode(rtwdev); + rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_START: mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, true, params); + rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, true, params); mutex_unlock(&rtwdev->mutex); break; case IEEE80211_AMPDU_RX_STOP: mutex_lock(&rtwdev->mutex); - rtw89_fw_h2c_ba_cam(rtwdev, rtwsta, false, params); + rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, false, params); mutex_unlock(&rtwdev->mutex); break; default: @@ -990,7 +994,7 @@ static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, } if (rtwdev->scanning) - rtw89_hw_scan_abort(rtwdev, vif); + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); if (type == IEEE80211_ROC_TYPE_MGMT_TX) roc->state = RTW89_ROC_MGMT; diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index be30c9346293..4befbe06cd15 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -1616,7 +1616,7 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { ret = rtw89_fw_h2c_notify_dbcc(rtwdev, true); if (ret) { - rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + rtw89_err(rtwdev, "%s:[ERR] notify dbcc1 fail %d\n", __func__, ret); return ret; } @@ -1625,7 +1625,7 @@ static int dbcc_enable_be(struct rtw89_dev *rtwdev, bool enable) if (test_bit(RTW89_FLAG_FW_RDY, rtwdev->flags)) { ret = rtw89_fw_h2c_notify_dbcc(rtwdev, false); if (ret) { - rtw89_err(rtwdev, "%s:[ERR]notfify dbcc1 fail %d\n", + rtw89_err(rtwdev, "%s:[ERR] notify dbcc1 fail %d\n", __func__, ret); return ret; } diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 769f1ce62ebc..9943ed856248 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -1907,22 +1907,87 @@ static int rtw89_write16_mdio_clr(struct rtw89_dev *rtwdev, u8 addr, u16 mask, u return 0; } +static int rtw89_dbi_write8(struct rtw89_dev *rtwdev, u16 addr, u8 data) +{ + u16 addr_2lsb = addr & B_AX_DBI_2LSB; + u16 write_addr; + u8 flag; + int ret; + + write_addr = addr & B_AX_DBI_ADDR_MSK; + write_addr |= u16_encode_bits(BIT(addr_2lsb), B_AX_DBI_WREN_MSK); + rtw89_write8(rtwdev, R_AX_DBI_WDATA + addr_2lsb, data); + rtw89_write16(rtwdev, R_AX_DBI_FLAG, write_addr); + rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_WFLAG >> 16); + + ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10, + 10 * RTW89_PCI_WR_RETRY_CNT, false, + rtwdev, R_AX_DBI_FLAG + 2); + if (ret) + rtw89_err(rtwdev, "failed to write DBI register, addr=0x%X\n", + addr); + + return ret; +} + +static int rtw89_dbi_read8(struct rtw89_dev *rtwdev, u16 addr, u8 *value) +{ + u16 read_addr = addr & B_AX_DBI_ADDR_MSK; + u8 flag; + int ret; + + rtw89_write16(rtwdev, R_AX_DBI_FLAG, read_addr); + rtw89_write8(rtwdev, R_AX_DBI_FLAG + 2, B_AX_DBI_RFLAG >> 16); + + ret = read_poll_timeout_atomic(rtw89_read8, flag, !flag, 10, + 10 * RTW89_PCI_WR_RETRY_CNT, false, + rtwdev, R_AX_DBI_FLAG + 2); + if (ret) { + rtw89_err(rtwdev, "failed to read DBI register, addr=0x%X\n", + addr); + return ret; + } + + read_addr = R_AX_DBI_RDATA + (addr & 3); + *value = rtw89_read8(rtwdev, read_addr); + + return 0; +} + static int rtw89_pci_write_config_byte(struct rtw89_dev *rtwdev, u16 addr, u8 data) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; struct pci_dev *pdev = rtwpci->pdev; + int ret; + + ret = pci_write_config_byte(pdev, addr, data); + if (!ret) + return 0; - return pci_write_config_byte(pdev, addr, data); + if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + ret = rtw89_dbi_write8(rtwdev, addr, data); + + return ret; } static int rtw89_pci_read_config_byte(struct rtw89_dev *rtwdev, u16 addr, u8 *value) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; struct pci_dev *pdev = rtwpci->pdev; + int ret; - return pci_read_config_byte(pdev, addr, value); + ret = pci_read_config_byte(pdev, addr, value); + if (!ret) + return 0; + + if (chip_id == RTL8852A || chip_id == RTL8852B || chip_id == RTL8851B) + ret = rtw89_dbi_read8(rtwdev, addr, value); + + return ret; } static int rtw89_pci_config_byte_set(struct rtw89_dev *rtwdev, u16 addr, diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index ca5de77fee90..1fb7c209fa0d 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -42,6 +42,7 @@ #define B_AX_DBI_WFLAG BIT(16) #define B_AX_DBI_WREN_MSK GENMASK(15, 12) #define B_AX_DBI_ADDR_MSK GENMASK(11, 2) +#define B_AX_DBI_2LSB GENMASK(1, 0) #define R_AX_DBI_WDATA 0x1094 #define R_AX_DBI_RDATA 0x1098 diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index bafc7b1cc104..7880fbaee092 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -905,6 +905,8 @@ static void rtw89_phy_config_bb_reg(struct rtw89_dev *rtwdev, udelay(5); else if (reg->addr == 0xf9) udelay(1); + else if (reg->data == BYPASS_CR_DATA) + rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "Bypass CR 0x%x\n", reg->addr); else rtw89_phy_write32(rtwdev, reg->addr, reg->data); } @@ -929,7 +931,7 @@ static void rtw89_phy_cfg_bb_gain_error(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; @@ -968,7 +970,7 @@ static void rtw89_phy_cfg_bb_rpl_ofst(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 rxsc_start = arg.rxsc_start; u8 bw = arg.bw; u8 path = arg.path; @@ -1050,7 +1052,7 @@ static void rtw89_phy_cfg_bb_gain_bypass(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; @@ -1077,7 +1079,7 @@ static void rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev, union rtw89_phy_bb_gain_arg arg, u32 data) { - struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 type = arg.type; u8 path = arg.path; u8 gband = arg.gain_band; @@ -1108,10 +1110,10 @@ rtw89_phy_cfg_bb_gain_op1db(struct rtw89_dev *rtwdev, } } -static void rtw89_phy_config_bb_gain(struct rtw89_dev *rtwdev, - const struct rtw89_reg2_def *reg, - enum rtw89_rf_path rf_path, - void *extra_data) +static void rtw89_phy_config_bb_gain_ax(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data) { const struct rtw89_chip_info *chip = rtwdev->chip; union rtw89_phy_bb_gain_arg arg = { .addr = reg->addr }; @@ -1425,7 +1427,7 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) bb_gain_table = elm_info->bb_gain ? elm_info->bb_gain : chip->bb_gain_table; if (bb_gain_table) rtw89_phy_init_reg(rtwdev, bb_gain_table, - rtw89_phy_config_bb_gain, NULL); + chip->phy_def->config_bb_gain, NULL); rtw89_phy_bb_reset(rtwdev, RTW89_PHY_0); } @@ -1467,11 +1469,9 @@ void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio) kfree(rf_reg_info); } -static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) +static void rtw89_phy_preinit_rf_nctl_ax(struct rtw89_dev *rtwdev) { - struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; const struct rtw89_chip_info *chip = rtwdev->chip; - const struct rtw89_phy_table *nctl_table; u32 val; int ret; @@ -1491,6 +1491,15 @@ static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) 1000, false, rtwdev); if (ret) rtw89_err(rtwdev, "failed to poll nctl block\n"); +} + +static void rtw89_phy_init_rf_nctl(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_phy_table *nctl_table; + + rtw89_phy_preinit_rf_nctl(rtwdev); nctl_table = elm_info->rf_nctl ? elm_info->rf_nctl : chip->nctl_table; rtw89_phy_init_reg(rtwdev, nctl_table, rtw89_phy_config_bb_reg, NULL); @@ -1561,6 +1570,7 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1); } +EXPORT_SYMBOL(rtw89_phy_set_phy_regs); void rtw89_phy_write_reg3_tbl(struct rtw89_dev *rtwdev, const struct rtw89_phy_reg3_tbl *tbl) @@ -4551,6 +4561,9 @@ static void rtw89_phy_dig_set_rxb_idx(struct rtw89_dev *rtwdev, u8 rxb_idx) static void rtw89_phy_dig_set_igi_cr(struct rtw89_dev *rtwdev, const struct rtw89_agc_gaincode_set set) { + if (!rtwdev->hal.support_igi) + return; + rtw89_phy_dig_set_lna_idx(rtwdev, set.lna_idx); rtw89_phy_dig_set_tia_idx(rtwdev, set.tia_idx); rtw89_phy_dig_set_rxb_idx(rtwdev, set.rxb_idx); @@ -4606,7 +4619,8 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, u8 rssi, s8 cck_cca_th; u32 pd_val = 0; - under_region += PD_TH_SB_FLTR_CMP_VAL; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) + under_region += PD_TH_SB_FLTR_CMP_VAL; switch (cbw) { case RTW89_CHANNEL_WIDTH_40: @@ -4953,7 +4967,9 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); + rtw89_phy_bb_wrap_init(rtwdev); rtw89_phy_edcca_init(rtwdev); + rtw89_phy_ch_info_init(rtwdev); rtw89_phy_ul_tb_info_init(rtwdev); rtw89_phy_antdiv_init(rtwdev); rtw89_chip_rfe_gpio(rtwdev); @@ -5476,6 +5492,10 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_ax = { .ccx = &rtw89_ccx_regs_ax, .physts = &rtw89_physts_regs_ax, .cfo = &rtw89_cfo_regs_ax, + .config_bb_gain = rtw89_phy_config_bb_gain_ax, + .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_ax, + .bb_wrap_init = NULL, + .ch_info_init = NULL, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_ax, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_ax, diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 3e379077c6ca..c05f724a84ce 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -7,6 +7,7 @@ #include "core.h" +#define RTW89_BBMCU_ADDR_OFFSET 0x30000 #define RTW89_RF_ADDR_ADSEL_MASK BIT(16) #define get_phy_headline(addr) FIELD_GET(GENMASK(31, 28), addr) @@ -509,6 +510,13 @@ struct rtw89_phy_gen_def { const struct rtw89_ccx_regs *ccx; const struct rtw89_physts_regs *physts; const struct rtw89_cfo_regs *cfo; + void (*config_bb_gain)(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data); + void (*preinit_rf_nctl)(struct rtw89_dev *rtwdev); + void (*bb_wrap_init)(struct rtw89_dev *rtwdev); + void (*ch_info_init)(struct rtw89_dev *rtwdev); void (*set_txpwr_byrate)(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, @@ -604,6 +612,15 @@ static inline u32 rtw89_phy_read32_mask(struct rtw89_dev *rtwdev, return rtw89_read32_mask(rtwdev, addr + phy->cr_base, mask); } +static inline void rtw89_bbmcu_write32(struct rtw89_dev *rtwdev, + u32 addr, u32 data, enum rtw89_phy_idx phy_idx) +{ + if (phy_idx && addr < 0x10000) + addr += 0x20000; + + rtw89_write32(rtwdev, addr + RTW89_BBMCU_ADDR_OFFSET, data); +} + static inline enum rtw89_gain_offset rtw89_subband_to_gain_offset_band_of_ofdm(enum rtw89_subband subband) { @@ -664,6 +681,38 @@ enum rtw89_phy_bb_gain_band rtw89_subband_to_bb_gain_band(enum rtw89_subband sub } } +static inline +enum rtw89_phy_gain_band_be rtw89_subband_to_gain_band_be(enum rtw89_subband subband) +{ + switch (subband) { + default: + case RTW89_CH_2G: + return RTW89_BB_GAIN_BAND_2G_BE; + case RTW89_CH_5G_BAND_1: + return RTW89_BB_GAIN_BAND_5G_L_BE; + case RTW89_CH_5G_BAND_3: + return RTW89_BB_GAIN_BAND_5G_M_BE; + case RTW89_CH_5G_BAND_4: + return RTW89_BB_GAIN_BAND_5G_H_BE; + case RTW89_CH_6G_BAND_IDX0: + return RTW89_BB_GAIN_BAND_6G_L0_BE; + case RTW89_CH_6G_BAND_IDX1: + return RTW89_BB_GAIN_BAND_6G_L1_BE; + case RTW89_CH_6G_BAND_IDX2: + return RTW89_BB_GAIN_BAND_6G_M0_BE; + case RTW89_CH_6G_BAND_IDX3: + return RTW89_BB_GAIN_BAND_6G_M1_BE; + case RTW89_CH_6G_BAND_IDX4: + return RTW89_BB_GAIN_BAND_6G_H0_BE; + case RTW89_CH_6G_BAND_IDX5: + return RTW89_BB_GAIN_BAND_6G_H1_BE; + case RTW89_CH_6G_BAND_IDX6: + return RTW89_BB_GAIN_BAND_6G_UH0_BE; + case RTW89_CH_6G_BAND_IDX7: + return RTW89_BB_GAIN_BAND_6G_UH1_BE; + } +} + enum rtw89_rfk_flag { RTW89_RFK_F_WRF = 0, RTW89_RFK_F_WM = 1, @@ -759,6 +808,29 @@ s8 rtw89_phy_read_txpwr_limit(struct rtw89_dev *rtwdev, u8 band, s8 rtw89_phy_read_txpwr_limit_ru(struct rtw89_dev *rtwdev, u8 band, u8 ru, u8 ntx, u8 ch); +static inline void rtw89_phy_preinit_rf_nctl(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + phy->preinit_rf_nctl(rtwdev); +} + +static inline void rtw89_phy_bb_wrap_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + if (phy->bb_wrap_init) + phy->bb_wrap_init(rtwdev); +} + +static inline void rtw89_phy_ch_info_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + + if (phy->ch_info_init) + phy->ch_info_init(rtwdev); +} + static inline void rtw89_phy_set_txpwr_byrate(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index 63eeeea72b68..6849438a5f3c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -78,6 +78,314 @@ static const struct rtw89_cfo_regs rtw89_cfo_regs_be = { .valid_0_mask = B_DCFO_OPT_EN_V1, }; +union rtw89_phy_bb_gain_arg_be { + u32 addr; + struct { + u8 type; +#define BB_GAIN_TYPE_SUB0_BE GENMASK(3, 0) +#define BB_GAIN_TYPE_SUB1_BE GENMASK(7, 4) + u8 path_bw; +#define BB_GAIN_PATH_BE GENMASK(3, 0) +#define BB_GAIN_BW_BE GENMASK(7, 4) + u8 gain_band; + u8 cfg_type; + } __packed; +} __packed; + +static void +rtw89_phy_cfg_bb_gain_error_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 type = arg.type; + int i; + + switch (type) { + case 0: + for (i = 0; i < 4; i++, data >>= 8) + gain->lna_gain[gband][bw_type][path][i] = data & 0xff; + break; + case 1: + for (i = 4; i < 7; i++, data >>= 8) + gain->lna_gain[gband][bw_type][path][i] = data & 0xff; + break; + case 2: + for (i = 0; i < 2; i++, data >>= 8) + gain->tia_gain[gband][bw_type][path][i] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb gain error {0x%x:0x%x} with unknown type: %d\n", + arg.addr, data, type); + break; + } +} + +static void +rtw89_phy_cfg_bb_rpl_ofst_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 type_sub0 = u8_get_bits(arg.type, BB_GAIN_TYPE_SUB0_BE); + u8 type_sub1 = u8_get_bits(arg.type, BB_GAIN_TYPE_SUB1_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 ofst = 0; + int i; + + switch (type_sub1) { + case RTW89_CMAC_BW_20M: + gain->rpl_ofst_20[gband][path][0] = (s8)data; + break; + case RTW89_CMAC_BW_40M: + for (i = 0; i < RTW89_BW20_SC_40M; i++, data >>= 8) + gain->rpl_ofst_40[gband][path][i] = data & 0xff; + break; + case RTW89_CMAC_BW_80M: + for (i = 0; i < RTW89_BW20_SC_80M; i++, data >>= 8) + gain->rpl_ofst_80[gband][path][i] = data & 0xff; + break; + case RTW89_CMAC_BW_160M: + if (type_sub0 == 0) + ofst = 0; + else + ofst = RTW89_BW20_SC_80M; + + for (i = 0; i < RTW89_BW20_SC_80M; i++, data >>= 8) + gain->rpl_ofst_160[gband][path][i + ofst] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb rpl ofst {0x%x:0x%x} with unknown type_sub1: %d\n", + arg.addr, data, type_sub1); + break; + } +} + +static void +rtw89_phy_cfg_bb_gain_op1db_be(struct rtw89_dev *rtwdev, + union rtw89_phy_bb_gain_arg_be arg, u32 data) +{ + struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + u8 gband = arg.gain_band; + u8 type = arg.type; + int i; + + switch (type) { + case 0: + for (i = 0; i < 4; i++, data >>= 8) + gain->lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 1: + for (i = 4; i < 7; i++, data >>= 8) + gain->lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 2: + for (i = 0; i < 4; i++, data >>= 8) + gain->tia_lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + case 3: + for (i = 4; i < 8; i++, data >>= 8) + gain->tia_lna_op1db[gband][bw_type][path][i] = data & 0xff; + break; + default: + rtw89_warn(rtwdev, + "bb gain op1db {0x%x:0x%x} with unknown type: %d\n", + arg.addr, data, type); + break; + } +} + +static void rtw89_phy_config_bb_gain_be(struct rtw89_dev *rtwdev, + const struct rtw89_reg2_def *reg, + enum rtw89_rf_path rf_path, + void *extra_data) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + union rtw89_phy_bb_gain_arg_be arg = { .addr = reg->addr }; + struct rtw89_efuse *efuse = &rtwdev->efuse; + u8 bw_type = u8_get_bits(arg.path_bw, BB_GAIN_BW_BE); + u8 path = u8_get_bits(arg.path_bw, BB_GAIN_PATH_BE); + + if (bw_type >= RTW89_BB_BW_NR_BE) + return; + + if (arg.gain_band >= RTW89_BB_GAIN_BAND_NR_BE) + return; + + if (path >= chip->rf_path_num) + return; + + if (arg.addr >= 0xf9 && arg.addr <= 0xfe) { + rtw89_warn(rtwdev, "bb gain table with flow ctrl\n"); + return; + } + + switch (arg.cfg_type) { + case 0: + rtw89_phy_cfg_bb_gain_error_be(rtwdev, arg, reg->data); + break; + case 1: + rtw89_phy_cfg_bb_rpl_ofst_be(rtwdev, arg, reg->data); + break; + case 2: + /* ignore BB gain bypass */ + break; + case 3: + rtw89_phy_cfg_bb_gain_op1db_be(rtwdev, arg, reg->data); + break; + case 4: + /* This cfg_type is only used by rfe_type >= 50 with eFEM */ + if (efuse->rfe_type < 50) + break; + fallthrough; + default: + rtw89_warn(rtwdev, + "bb gain {0x%x:0x%x} with unknown cfg type: %d\n", + arg.addr, reg->data, arg.cfg_type); + break; + } +} + +static void rtw89_phy_preinit_rf_nctl_be(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_GOTX_IQKDPK_C0, B_GOTX_IQKDPK, 0x3); + rtw89_phy_write32_mask(rtwdev, R_GOTX_IQKDPK_C1, B_GOTX_IQKDPK, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQKDPK_HC, B_IQKDPK_HC, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CLK_GCK, B_CLK_GCK, 0x00fffff); + rtw89_phy_write32_mask(rtwdev, R_IOQ_IQK_DPK, B_IOQ_IQK_DPK_CLKEN, 0x3); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_PRST, B_IQK_DPK_PRST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_PRST_C1, B_IQK_DPK_PRST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TXRFC, B_TXRFC_RST, 0x1); + + if (rtwdev->dbcc_en) { + rtw89_phy_write32_mask(rtwdev, R_IQK_DPK_RST_C1, B_IQK_DPK_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_TXRFC_C1, B_TXRFC_RST, 0x1); + } +} + +static +void rtw89_phy_bb_wrap_pwr_by_macid_init(struct rtw89_dev *rtwdev) +{ + u32 macid_idx, cr, base_macid_lmt, max_macid = 32; + + base_macid_lmt = R_BE_PWR_MACID_LMT_BASE; + + for (macid_idx = 0; macid_idx < 4 * max_macid; macid_idx += 4) { + cr = base_macid_lmt + macid_idx; + rtw89_write32(rtwdev, cr, 0x03007F7F); + } +} + +static +void rtw89_phy_bb_wrap_tx_path_by_macid_init(struct rtw89_dev *rtwdev) +{ + int i, max_macid = 32; + u32 cr = R_BE_PWR_MACID_PATH_BASE; + + for (i = 0; i < max_macid; i++, cr += 4) + rtw89_write32(rtwdev, cr, 0x03C86000); +} + +static void rtw89_phy_bb_wrap_tpu_set_all(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + for (addr = R_BE_PWR_BY_RATE; addr <= R_BE_PWR_BY_RATE_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + for (addr = R_BE_PWR_RULMT_START; addr <= R_BE_PWR_RULMT_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + for (addr = R_BE_PWR_RATE_OFST_CTRL; addr <= R_BE_PWR_RATE_OFST_END; addr += 4) + rtw89_write32(rtwdev, addr, 0); + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_REF_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_LMT_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_LMTBF, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_LMTBF_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_RATE_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_BYRATE_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_RULMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_RULMT_DB, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_SW, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_OFST_SW_DB, 0); +} + +static +void rtw89_phy_bb_wrap_listen_path_en_init(struct rtw89_dev *rtwdev) +{ + u32 addr; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_1, RTW89_CMAC_SEL); + if (ret) + return; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_LISTEN_PATH, RTW89_MAC_1); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_LISTEN_PATH_EN, 0x2); +} + +static void rtw89_phy_bb_wrap_force_cr_init(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FORCE_LMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_LMT_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RATE_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_OFST_RULMT, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ENON, 0); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_RU_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FORCE_MACID, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_MACID_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_COEX_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_PWR_FORCE_COEX_ON, 0); + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_RATE_CTRL, mac_idx); + rtw89_write32_mask(rtwdev, addr, B_BE_FORCE_PWR_BY_RATE_EN, 0); +} + +static void rtw89_phy_bb_wrap_ftm_init(struct rtw89_dev *rtwdev, + enum rtw89_mac_idx mac_idx) +{ + u32 addr; + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FTM, mac_idx); + rtw89_write32(rtwdev, addr, 0xE4E431); + + addr = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_FTM_SS, mac_idx); + rtw89_write32_mask(rtwdev, addr, 0x7, 0); +} + +static void rtw89_phy_bb_wrap_init_be(struct rtw89_dev *rtwdev) +{ + enum rtw89_mac_idx mac_idx = RTW89_MAC_0; + + rtw89_phy_bb_wrap_pwr_by_macid_init(rtwdev); + rtw89_phy_bb_wrap_tx_path_by_macid_init(rtwdev); + rtw89_phy_bb_wrap_listen_path_en_init(rtwdev); + rtw89_phy_bb_wrap_force_cr_init(rtwdev, mac_idx); + rtw89_phy_bb_wrap_ftm_init(rtwdev, mac_idx); + rtw89_phy_bb_wrap_tpu_set_all(rtwdev, mac_idx); +} + +static void rtw89_phy_ch_info_init_be(struct rtw89_dev *rtwdev) +{ + rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG_LEN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CHINFO_SEG, B_CHINFO_SEG, 0xf); + rtw89_phy_write32_mask(rtwdev, R_CHINFO_DATA, B_CHINFO_DATA_BITMAP, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_ELM_SRC, B_CHINFO_ELM_BITMAP, 0x40303); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_ELM_SRC, B_CHINFO_SRC, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_TYPE_SCAL, B_CHINFO_TYPE, 0x3); + rtw89_phy_set_phy_regs(rtwdev, R_CHINFO_TYPE_SCAL, B_CHINFO_SCAL, 0x0); +} + struct rtw89_byr_spec_ent_be { struct rtw89_rate_desc init; u8 num_of_idx; @@ -644,6 +952,10 @@ const struct rtw89_phy_gen_def rtw89_phy_gen_be = { .ccx = &rtw89_ccx_regs_be, .physts = &rtw89_physts_regs_be, .cfo = &rtw89_cfo_regs_be, + .config_bb_gain = rtw89_phy_config_bb_gain_be, + .preinit_rf_nctl = rtw89_phy_preinit_rf_nctl_be, + .bb_wrap_init = rtw89_phy_bb_wrap_init_be, + .ch_info_init = rtw89_phy_ch_info_init_be, .set_txpwr_byrate = rtw89_phy_set_txpwr_byrate_be, .set_txpwr_offset = rtw89_phy_set_txpwr_offset_be, diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index 8456e2b0c14f..acc96d30d085 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -4033,6 +4033,30 @@ #define B_BE_SYSON_DIS_PMCR_BE_WRMSK BIT(2) #define B_BE_SYSON_R_BE_ARB_MASK GENMASK(1, 0) +#define R_BE_MEM_PWR_CTRL 0x00D0 +#define B_BE_DMEM5_WLMCU_DS BIT(31) +#define B_BE_DMEM4_WLMCU_DS BIT(30) +#define B_BE_DMEM3_WLMCU_DS BIT(29) +#define B_BE_DMEM2_WLMCU_DS BIT(28) +#define B_BE_DMEM1_WLMCU_DS BIT(27) +#define B_BE_DMEM0_WLMCU_DS BIT(26) +#define B_BE_IMEM5_WLMCU_DS BIT(25) +#define B_BE_IMEM4_WLMCU_DS BIT(24) +#define B_BE_IMEM3_WLMCU_DS BIT(23) +#define B_BE_IMEM2_WLMCU_DS BIT(22) +#define B_BE_IMEM1_WLMCU_DS BIT(21) +#define B_BE_IMEM0_WLMCU_DS BIT(20) +#define B_BE_MEM_BBMCU1_DS BIT(19) +#define B_BE_MEM_BBMCU0_DS_V1 BIT(17) +#define B_BE_MEM_BT_DS BIT(10) +#define B_BE_MEM_SDIO_LS BIT(9) +#define B_BE_MEM_SDIO_DS BIT(8) +#define B_BE_MEM_USB_LS BIT(7) +#define B_BE_MEM_USB_DS BIT(6) +#define B_BE_MEM_PCI_LS BIT(5) +#define B_BE_MEM_PCI_DS BIT(4) +#define B_BE_MEM_WLMAC_LS BIT(3) + #define R_BE_PCIE_MIO_INTF 0x00E4 #define B_BE_AON_MIO_EPHY_1K_SEL_MASK GENMASK(29, 24) #define B_BE_PCIE_MIO_ADDR_PAGE_V1_MASK GENMASK(20, 16) @@ -4401,6 +4425,19 @@ #define R_BE_LTR_LATENCY_IDX2_V1 0x361C #define R_BE_LTR_LATENCY_IDX3_V1 0x3620 +#define R_BE_H2CREG_DATA0 0x7140 +#define R_BE_H2CREG_DATA1 0x7144 +#define R_BE_H2CREG_DATA2 0x7148 +#define R_BE_H2CREG_DATA3 0x714C +#define R_BE_C2HREG_DATA0 0x7150 +#define R_BE_C2HREG_DATA1 0x7154 +#define R_BE_C2HREG_DATA2 0x7158 +#define R_BE_C2HREG_DATA3 0x715C +#define R_BE_H2CREG_CTRL 0x7160 +#define B_BE_H2CREG_TRIGGER BIT(0) +#define R_BE_C2HREG_CTRL 0x7164 +#define B_BE_C2HREG_TRIGGER BIT(0) + #define R_BE_HCI_FUNC_EN 0x7880 #define B_BE_HCI_CR_PROTECT BIT(31) #define B_BE_HCI_TRXBUF_EN BIT(2) @@ -4488,6 +4525,42 @@ #define B_BE_RMAC_PPDU_HANG_CNT_MASK GENMASK(23, 16) #define B_BE_SER_L0_COUNTER_MASK GENMASK(8, 0) +#define R_BE_DMAC_SYS_CR32B 0x842C +#define B_BE_DMAC_BB_PHY1_MASK GENMASK(31, 16) +#define B_BE_DMAC_BB_PHY0_MASK GENMASK(15, 0) +#define B_BE_DMAC_BB_CTRL_39 BIT(31) +#define B_BE_DMAC_BB_CTRL_38 BIT(30) +#define B_BE_DMAC_BB_CTRL_37 BIT(29) +#define B_BE_DMAC_BB_CTRL_36 BIT(28) +#define B_BE_DMAC_BB_CTRL_35 BIT(27) +#define B_BE_DMAC_BB_CTRL_34 BIT(26) +#define B_BE_DMAC_BB_CTRL_33 BIT(25) +#define B_BE_DMAC_BB_CTRL_32 BIT(24) +#define B_BE_DMAC_BB_CTRL_31 BIT(23) +#define B_BE_DMAC_BB_CTRL_30 BIT(22) +#define B_BE_DMAC_BB_CTRL_29 BIT(21) +#define B_BE_DMAC_BB_CTRL_28 BIT(20) +#define B_BE_DMAC_BB_CTRL_27 BIT(19) +#define B_BE_DMAC_BB_CTRL_26 BIT(18) +#define B_BE_DMAC_BB_CTRL_25 BIT(17) +#define B_BE_DMAC_BB_CTRL_24 BIT(16) +#define B_BE_DMAC_BB_CTRL_23 BIT(15) +#define B_BE_DMAC_BB_CTRL_22 BIT(14) +#define B_BE_DMAC_BB_CTRL_21 BIT(13) +#define B_BE_DMAC_BB_CTRL_20 BIT(12) +#define B_BE_DMAC_BB_CTRL_19 BIT(11) +#define B_BE_DMAC_BB_CTRL_18 BIT(10) +#define B_BE_DMAC_BB_CTRL_17 BIT(9) +#define B_BE_DMAC_BB_CTRL_16 BIT(8) +#define B_BE_DMAC_BB_CTRL_15 BIT(7) +#define B_BE_DMAC_BB_CTRL_14 BIT(6) +#define B_BE_DMAC_BB_CTRL_13 BIT(5) +#define B_BE_DMAC_BB_CTRL_12 BIT(4) +#define B_BE_DMAC_BB_CTRL_11 BIT(3) +#define B_BE_DMAC_BB_CTRL_10 BIT(2) +#define B_BE_DMAC_BB_CTRL_9 BIT(1) +#define B_BE_DMAC_BB_CTRL_8 BIT(0) + #define R_BE_DLE_EMPTY0 0x8430 #define B_BE_PLE_EMPTY_QTA_DMAC_H2D BIT(27) #define B_BE_PLE_EMPTY_QTA_DMAC_CPUIO BIT(26) @@ -5777,6 +5850,15 @@ #define B_BE_PREC_PAGE_CH12_V1_MASK GENMASK(21, 16) #define B_BE_PREC_PAGE_CH011_V1_MASK GENMASK(5, 0) +#define R_BE_CH0_PAGE_CTRL 0xB718 +#define B_BE_CH0_GRP BIT(31) +#define B_BE_CH0_MAX_PG_MASK GENMASK(28, 16) +#define B_BE_CH0_MIN_PG_MASK GENMASK(12, 0) + +#define R_BE_CH0_PAGE_INFO 0xB750 +#define B_BE_CH0_AVAL_PG_MASK GENMASK(28, 16) +#define B_BE_CH0_USE_PG_MASK GENMASK(12, 0) + #define R_BE_PUB_PAGE_INFO3 0xB78C #define B_BE_G1_AVAL_PG_MASK GENMASK(28, 16) #define B_BE_G0_AVAL_PG_MASK GENMASK(12, 0) @@ -5822,6 +5904,9 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_PWR_MACID_PATH_BASE 0x0E500 +#define R_BE_PWR_MACID_LMT_BASE 0x0ED00 + #define R_BE_CMAC_FUNC_EN 0x10000 #define R_BE_CMAC_FUNC_EN_C1 0x14000 #define B_BE_CMAC_CRPRT BIT(31) @@ -7178,12 +7263,56 @@ #define R_BE_PWR_MODULE 0x11900 #define R_BE_PWR_MODULE_C1 0x15900 +#define R_BE_PWR_LISTEN_PATH 0x11988 +#define B_BE_PWR_LISTEN_PATH_EN GENMASK(31, 28) + +#define R_BE_PWR_REF_CTRL 0x11A20 +#define B_BE_PWR_REF_CTRL_OFDM GENMASK(9, 1) +#define B_BE_PWR_REF_CTRL_CCK GENMASK(18, 10) +#define B_BE_PWR_OFST_LMT_DB GENMASK(27, 19) +#define R_BE_PWR_OFST_LMTBF 0x11A24 +#define B_BE_PWR_OFST_LMTBF_DB GENMASK(8, 0) +#define R_BE_PWR_FORCE_LMT 0x11A28 +#define B_BE_PWR_FORCE_LMT_ON BIT(6) + +#define R_BE_PWR_RATE_CTRL 0x11A2C +#define B_BE_PWR_OFST_BYRATE_DB GENMASK(8, 0) +#define B_BE_FORCE_PWR_BY_RATE_EN BIT(19) +#define B_BE_FORCE_PWR_BY_RATE_VAL GENMASK(28, 20) #define R_BE_PWR_RATE_OFST_CTRL 0x11A30 +#define R_BE_PWR_RATE_OFST_END 0x11A38 +#define R_BE_PWR_RULMT_START 0x12048 +#define R_BE_PWR_RULMT_END 0x120e4 + +#define R_BE_PWR_BOOST 0x11A40 +#define B_BE_PWR_CTRL_SEL BIT(16) +#define B_BE_PWR_FORCE_RATE_ON BIT(29) +#define R_BE_PWR_OFST_RULMT 0x11A44 +#define B_BE_PWR_OFST_RULMT_DB GENMASK(17, 9) +#define B_BE_PWR_FORCE_RU_ON BIT(18) +#define B_BE_PWR_FORCE_RU_ENON BIT(28) +#define R_BE_PWR_FORCE_MACID 0x11A48 +#define B_BE_PWR_FORCE_MACID_ON BIT(9) + +#define R_BE_PWR_REG_CTRL 0x11A50 +#define B_BE_PWR_BT_EN BIT(23) + +#define R_BE_PWR_COEX_CTRL 0x11A54 +#define B_BE_PWR_BT_VAL GENMASK(8, 0) +#define B_BE_PWR_FORCE_COEX_ON GENMASK(29, 27) + +#define R_BE_PWR_OFST_SW 0x11AE8 +#define B_BE_PWR_OFST_SW_DB GENMASK(27, 24) + +#define R_BE_PWR_FTM 0x11B00 +#define R_BE_PWR_FTM_SS 0x11B04 + #define R_BE_PWR_BY_RATE 0x11E00 #define R_BE_PWR_BY_RATE_MAX 0x11FA8 #define R_BE_PWR_LMT 0x11FAC #define R_BE_PWR_LMT_MAX 0x12040 +#define R_BE_PWR_BY_RATE_END 0x12044 #define R_BE_PWR_RU_LMT 0x12048 #define R_BE_PWR_RU_LMT_MAX 0x120E4 @@ -7325,8 +7454,12 @@ #define RR_TXAC 0x5f #define RR_TXAC_IQG GENMASK(3, 0) #define RR_BIASA 0x60 -#define RR_BIASA_TXG GENMASK(15, 12) #define RR_BIASA_TXA GENMASK(19, 16) +#define RR_BIASA_TXG GENMASK(15, 12) +#define RR_BIASD_TXA_V1 GENMASK(15, 12) +#define RR_BIASA_TXA_V1 GENMASK(11, 8) +#define RR_BIASD_TXG_V1 GENMASK(7, 4) +#define RR_BIASA_TXG_V1 GENMASK(3, 0) #define RR_BIASA_A GENMASK(2, 0) #define RR_BIASA2 0x63 #define RR_BIASA2_LB GENMASK(4, 2) @@ -7459,15 +7592,24 @@ #define RR_RFC_CKEN BIT(1) #define R_UPD_P0 0x0000 +#define R_BBCLK 0x0000 +#define B_CLK_640M BIT(2) #define R_RSTB_WATCH_DOG 0x000C #define B_P0_RSTB_WATCH_DOG BIT(0) #define B_P1_RSTB_WATCH_DOG BIT(1) #define B_UPD_P0_EN BIT(31) +#define R_EMLSR 0x0044 +#define B_EMLSR_PARM GENMASK(27, 12) #define R_SPOOF_CG 0x00B4 #define B_SPOOF_CG_EN BIT(17) +#define R_CHINFO_SEG 0x00B4 +#define B_CHINFO_SEG_LEN GENMASK(2, 0) +#define B_CHINFO_SEG GENMASK(16, 7) #define R_DFS_FFT_CG 0x00B8 #define B_DFS_CG_EN BIT(1) #define B_DFS_FFT_EN BIT(0) +#define R_CHINFO_DATA 0x00C0 +#define B_CHINFO_DATA_BITMAP GENMASK(22, 0) #define R_ANAPAR_PW15 0x030C #define B_ANAPAR_PW15 GENMASK(31, 24) #define B_ANAPAR_PW15_H GENMASK(27, 24) @@ -7497,6 +7639,9 @@ #define B_SWSI_READ_ADDR_ADDR_V1 GENMASK(7, 0) #define B_SWSI_READ_ADDR_PATH_V1 GENMASK(10, 8) #define B_SWSI_READ_ADDR_V1 GENMASK(10, 0) +#define R_EN_SND_WO_NDP 0x047c +#define R_EN_SND_WO_NDP_C1 0x147c +#define B_EN_SND_WO_NDP BIT(1) #define R_UPD_CLK_ADC 0x0700 #define B_UPD_CLK_ADC_VAL GENMASK(26, 25) #define B_UPD_CLK_ADC_ON BIT(24) @@ -7588,19 +7733,28 @@ #define R_PD_CTRL 0x0C3C #define B_PD_HIT_DIS BIT(9) #define R_IOQ_IQK_DPK 0x0C60 +#define B_IOQ_IQK_DPK_CLKEN GENMASK(1, 0) #define B_IOQ_IQK_DPK_EN BIT(1) #define R_GNT_BT_WGT_EN 0x0C6C #define B_GNT_BT_WGT_EN BIT(21) +#define R_IQK_DPK_RST 0x0C6C +#define R_IQK_DPK_RST_C1 0x1C6C +#define B_IQK_DPK_RST BIT(0) #define R_TX_COLLISION_T2R_ST 0x0C70 #define B_TX_COLLISION_T2R_ST_M GENMASK(25, 20) #define R_TXGATING 0x0C74 #define B_TXGATING_EN BIT(4) +#define R_TXRFC 0x0C7C +#define R_TXRFC_C1 0x1C7C +#define B_TXRFC_RST GENMASK(23, 21) #define R_PD_ARBITER_OFF 0x0C80 #define B_PD_ARBITER_OFF BIT(31) #define R_SNDCCA_A1 0x0C9C #define B_SNDCCA_A1_EN GENMASK(19, 12) #define R_SNDCCA_A2 0x0CA0 #define B_SNDCCA_A2_VAL GENMASK(19, 12) +#define R_UDP_COEEF 0x0CBC +#define B_UDP_COEEF BIT(19) #define R_TX_COLLISION_T2R_ST_BE 0x0CC8 #define B_TX_COLLISION_T2R_ST_BE_M GENMASK(13, 8) #define R_RXHT_MCS_LIMIT 0x0D18 @@ -7624,6 +7778,8 @@ #define R_CTLTOP 0x1008 #define B_CTLTOP_ON BIT(23) #define B_CTLTOP_VAL GENMASK(15, 12) +#define R_CLK_GCK 0x1008 +#define B_CLK_GCK GENMASK(24, 0) #define R_EDCCA_RPT_SEL_BE 0x10CC #define R_S0_HW_SI_DIS 0x1200 #define B_S0_HW_SI_DIS_W_R_TRIG GENMASK(30, 28) @@ -7771,6 +7927,12 @@ #define B_P80_AT_HIGH_FREQ_RU_ALLOC_PHY0 BIT(13) #define R_DBCC_80P80_SEL_EVM_RPT2 0x2A10 #define B_DBCC_80P80_SEL_EVM_RPT2_EN BIT(0) +#define R_AFEDAC0 0x2A5C +#define B_AFEDAC0 GENMASK(31, 27) +#define R_AFEDAC1 0x2A60 +#define B_AFEDAC1 GENMASK(2, 0) +#define R_IQKDPK_HC 0x2AB8 +#define B_IQKDPK_HC BIT(28) #define R_P1_EN_SOUND_WO_NDP 0x2D7C #define B_P1_EN_SOUND_WO_NDP BIT(1) #define R_EDCCA_RPT_A_BE 0x2E38 @@ -7806,8 +7968,28 @@ #define R_S1_ADDCK 0x3E00 #define B_S1_ADDCK_I GENMASK(9, 0) #define B_S1_ADDCK_Q GENMASK(19, 10) +#define R_OP1DB_A 0x406B +#define B_OP1DB_A GENMASK(31, 24) +#define R_OP1DB1_A 0x40BC +#define B_TIA1_A GENMASK(15, 8) +#define B_TIA0_A GENMASK(7, 0) +#define R_BKOFF_A 0x40E0 +#define B_BKOFF_IBADC_A GENMASK(23, 18) +#define R_BACKOFF_A 0x40E4 +#define B_BACKOFF_LNA_A GENMASK(29, 24) +#define B_BACKOFF_IBADC_A GENMASK(23, 18) +#define R_RXBY_WBADC_A 0x40F4 +#define B_RXBY_WBADC_A GENMASK(14, 10) #define R_MUIC 0x40F8 #define B_MUIC_EN BIT(0) +#define R_BT_RXBY_WBADC_A 0x4160 +#define B_BT_RXBY_WBADC_A BIT(31) +#define R_BT_SHARE_A 0x4164 +#define B_BT_SHARE_A BIT(0) +#define B_BT_TRK_OFF_A BIT(1) +#define B_BTG_PATH_A BIT(4) +#define R_FORCE_FIR_A 0x418C +#define B_FORCE_FIR_A GENMASK(1, 0) #define R_DCFO 0x4264 #define B_DCFO GENMASK(7, 0) #define R_SEG0CSI 0x42AC @@ -7846,8 +8028,28 @@ #define R_DPD_BF 0x44a0 #define B_DPD_BF_OFDM GENMASK(16, 12) #define B_DPD_BF_SCA GENMASK(6, 0) +#define R_LNA_OP 0x44B0 +#define B_LNA6 GENMASK(31, 24) +#define R_LNA_TIA 0x44BC +#define B_TIA1_B GENMASK(15, 8) +#define B_TIA0_B GENMASK(7, 0) +#define R_BKOFF_B 0x44E0 +#define B_BKOFF_IBADC_B GENMASK(23, 18) +#define R_BACKOFF_B 0x44E4 +#define B_BACKOFF_LNA_B GENMASK(29, 24) +#define B_BACKOFF_IBADC_B GENMASK(23, 18) +#define R_RXBY_WBADC_B 0x44F4 +#define B_RXBY_WBADC_B GENMASK(14, 10) +#define R_BT_RXBY_WBADC_B 0x4560 +#define B_BT_RXBY_WBADC_B BIT(31) +#define R_BT_SHARE_B 0x4564 +#define B_BT_SHARE_B BIT(0) +#define B_BT_TRK_OFF_B BIT(1) +#define B_BTG_PATH_B BIT(4) #define R_TXPATH_SEL 0x458C #define B_TXPATH_SEL_MSK GENMASK(31, 28) +#define R_FORCE_FIR_B 0x458C +#define B_FORCE_FIR_B GENMASK(1, 0) #define R_TXPWR 0x4594 #define B_TXPWR_MSK GENMASK(30, 22) #define R_TXNSS_MAP 0x45B4 @@ -7910,10 +8112,12 @@ #define R_PATH0_P20_FOLLOW_BY_PAGCUGC 0x46A0 #define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V1 0x4C24 #define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V2 0x46E8 +#define R_PATH0_P20_FOLLOW_BY_PAGCUGC_V3 0x41C8 #define B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH0_S20_FOLLOW_BY_PAGCUGC 0x46A4 #define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V1 0x4C28 #define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V2 0x46EC +#define R_PATH0_S20_FOLLOW_BY_PAGCUGC_V3 0x41CC #define B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH0_RXB_INIT_V1 0x46A8 #define B_PATH0_RXB_INIT_IDX_MSK_V1 GENMASK(14, 10) @@ -7958,10 +8162,12 @@ #define R_PATH1_P20_FOLLOW_BY_PAGCUGC 0x4774 #define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V1 0x4CE8 #define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V2 0x47A8 +#define R_PATH1_P20_FOLLOW_BY_PAGCUGC_V3 0x45C8 #define B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH1_S20_FOLLOW_BY_PAGCUGC 0x4778 #define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V1 0x4CEC #define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V2 0x47AC +#define R_PATH1_S20_FOLLOW_BY_PAGCUGC_V3 0x45CC #define B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK BIT(5) #define R_PATH1_G_TIA0_LNA6_OP1DB_V1 0x4778 #define B_PATH1_G_TIA0_LNA6_OP1DB_V1 GENMASK(7, 0) @@ -8092,6 +8298,12 @@ #define B_PATH1_5MDET_SB2 BIT(8) #define B_PATH1_5MDET_SB0 BIT(6) #define B_PATH1_5MDET_TH GENMASK(5, 0) +#define R_CHINFO_ELM_SRC 0x4D84 +#define B_CHINFO_ELM_BITMAP GENMASK(22, 0) +#define B_CHINFO_SRC GENMASK(31, 30) +#define R_CHINFO_TYPE_SCAL 0x4D88 +#define B_CHINFO_TYPE GENMASK(2, 1) +#define B_CHINFO_SCAL BIT(8) #define R_RPL_BIAS_COMP 0x4DF0 #define B_RPL_BIAS_COMP_MASK GENMASK(7, 0) #define R_RPL_PATHAB 0x4E0C @@ -8241,12 +8453,58 @@ #define B_DCFO_WEIGHT_MSK_V1 GENMASK(31, 28) #define R_DCFO_OPT_V1 0x6260 #define B_DCFO_OPT_EN_V1 BIT(17) +#define R_TXFCTR 0x627C +#define B_TXFCTR_THD GENMASK(19, 10) +#define R_TXSCALE 0x6284 +#define B_TXFCTR_EN BIT(19) #define R_SEG0R_EDCCA_LVL_BE 0x69EC #define R_SEG0R_PPDU_LVL_BE 0x69F0 #define R_SEGSND 0x6A14 #define B_SEGSND_EN BIT(31) +#define R_DBCC 0x6B48 +#define B_DBCC_EN BIT(0) +#define R_FC0INV_SBW 0x6B50 +#define B_SMALLBW GENMASK(31, 30) +#define B_RX_BT_SG0 GENMASK(25, 22) +#define B_RX_1RCCA GENMASK(17, 14) +#define B_FC0_INV GENMASK(6, 0) +#define R_ANT_CHBW 0x6B54 +#define B_ANT_BT_SHARE BIT(16) +#define B_CHBW_BW GENMASK(14, 12) +#define B_CHBW_PRICH GENMASK(11, 8) +#define B_ANT_RX_SG0 GENMASK(3, 0) +#define R_SLOPE 0x6B6C +#define B_EHT_RATE_TH GENMASK(31, 28) +#define B_SLOPE_B GENMASK(27, 14) +#define B_SLOPE_A GENMASK(13, 0) +#define R_SC_CORNER 0x6B70 +#define B_SC_CORNER GENMASK(10, 0) +#define R_MAG_A 0x6BF4 +#define B_MGA_AEND GENMASK(31, 24) +#define R_MAG_AB 0x6BF8 +#define B_BY_SLOPE GENMASK(31, 24) +#define B_MAG_AB GENMASK(23, 0) +#define R_BEDGE 0x6BFC +#define B_EHT_MCS14 BIT(31) +#define B_HE_RATE_TH GENMASK(30, 27) +#define R_BEDGE2 0x6C00 +#define B_EHT_MCS15 BIT(31) +#define B_HT_VHT_TH GENMASK(11, 0) +#define R_BEDGE3 0x6C04 +#define B_TB_EN BIT(23) +#define B_HEMU_EN BIT(21) +#define B_HEERSU_EN BIT(19) +#define B_EHTTB_EN BIT(15) +#define B_BEDGE_CFG GENMASK(1, 0) +#define R_SU_PUNC 0x6C08 +#define B_SU_PUNC_EN BIT(1) +#define R_BEDGE5 0x6C10 +#define B_HWGEN_EN BIT(25) +#define B_PWROFST_COMP BIT(20) #define R_RPL_BIAS_COMP1 0x6DF0 #define B_RPL_BIAS_COMP1_MASK GENMASK(7, 0) +#define R_DBCC_FA 0x703C +#define B_DBCC_FA BIT(12) #define R_P1_TSSI_ALIM1 0x7630 #define B_P1_TSSI_ALIM1 GENMASK(29, 0) #define B_P1_TSSI_ALIM11 GENMASK(29, 20) @@ -8626,6 +8884,24 @@ #define B_DACKN0_V GENMASK(21, 14) #define R_DACKN1_CTL 0xC224 #define B_DACKN1_V GENMASK(21, 14) +#define R_GOTX_IQKDPK_C0 0xE464 +#define R_GOTX_IQKDPK_C1 0xE564 +#define B_GOTX_IQKDPK GENMASK(28, 27) +#define R_IQK_DPK_PRST 0xE4AC +#define R_IQK_DPK_PRST_C1 0xE5AC +#define B_IQK_DPK_PRST BIT(27) +#define R_TSSI_MAP_OFST_P0 0xE620 +#define R_TSSI_MAP_OFST_P1 0xE720 +#define B_TSSI_MAP_OFST_OFDM GENMASK(17, 9) +#define B_TSSI_MAP_OFST_CCK GENMASK(26, 18) +#define R_TXAGC_REF0_P0 0xE628 +#define R_TXAGC_REF0_P1 0xE728 +#define B_TXAGC_REF0_OFDM_DBM GENMASK(8, 0) +#define B_TXAGC_REF0_CCK_DBM GENMASK(17, 9) +#define B_TXAGC_REF0_OFDM_CW GENMASK(26, 18) +#define R_TXAGC_REF1_P0 0xE62C +#define R_TXAGC_REF1_P1 0xE72C +#define B_TXAGC_REF1_CCK_CW GENMASK(8, 0) /* WiFi CPU local domain */ #define R_AX_WDT_CTRL 0x0040 diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index 5c167a9278ce..09b23c56aa8e 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -901,7 +901,7 @@ static void rtw8851b_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; @@ -987,7 +987,7 @@ next: static void rtw8851b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 band = rtw89_subband_to_bb_gain_band(subband); u32 val; @@ -2299,6 +2299,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .enable_bb_rf = rtw8851b_mac_enable_bb_rf, .disable_bb_rf = rtw8851b_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8851b_bb_reset, .bb_sethw = rtw8851b_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, @@ -2334,6 +2335,12 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8851b_btc_set_rfe, .btc_init_cfg = rtw8851b_btc_init_cfg, @@ -2394,7 +2401,9 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .support_chanctx_num = 0, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = true, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 8cb5bde8f625..522883c8dfb9 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -5345,7 +5345,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 72, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 72, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, @@ -5353,7 +5353,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 72, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 72, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, @@ -5361,7 +5361,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 72, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 72, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CN][52] = 127, @@ -5793,7 +5793,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 74, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 74, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, @@ -5801,7 +5801,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 76, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 76, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, @@ -5809,7 +5809,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 76, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 76, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CN][52] = 127, @@ -6361,7 +6361,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 84, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 84, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, @@ -6369,7 +6369,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 84, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 84, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CN][51] = 127, @@ -6649,7 +6649,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 74, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 74, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CN][49] = 127, @@ -7975,7 +7975,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 42, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 42, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CN][48] = 127, @@ -7983,7 +7983,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 42, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CN][50] = 127, @@ -7991,7 +7991,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 40, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 40, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CN][52] = 127, @@ -8423,7 +8423,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 52, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 52, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CN][48] = 127, @@ -8431,7 +8431,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 52, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 52, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CN][50] = 127, @@ -8439,7 +8439,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 52, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 52, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CN][52] = 127, @@ -8871,7 +8871,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][48] = 64, [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, - [2][0][RTW89_IC][48] = 127, + [2][0][RTW89_IC][48] = 64, [2][0][RTW89_KCC][48] = 127, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CN][48] = 127, @@ -8879,7 +8879,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][50] = 64, [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, - [2][0][RTW89_IC][50] = 127, + [2][0][RTW89_IC][50] = 64, [2][0][RTW89_KCC][50] = 127, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CN][50] = 127, @@ -8887,7 +8887,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][52] = 60, [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, - [2][0][RTW89_IC][52] = 127, + [2][0][RTW89_IC][52] = 60, [2][0][RTW89_KCC][52] = 127, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CN][52] = 127, @@ -11055,7 +11055,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 72, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 72, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CN][48] = 127, @@ -11063,7 +11063,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 72, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 72, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CN][50] = 127, @@ -11071,7 +11071,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 72, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 72, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CN][52] = 127, @@ -11503,7 +11503,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 74, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 74, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CN][48] = 127, @@ -11511,7 +11511,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 74, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 74, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CN][50] = 127, @@ -11519,7 +11519,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 74, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 74, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CN][52] = 127, @@ -12071,7 +12071,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 80, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 80, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CN][47] = 127, @@ -12079,7 +12079,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 80, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 80, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CN][51] = 127, @@ -12359,7 +12359,7 @@ const s8 rtw89_8851b_txpwr_lmt_5g_type2[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 72, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 72, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CN][49] = 127, @@ -13685,7 +13685,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 40, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 40, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CN][48] = 127, @@ -13693,7 +13693,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 42, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CN][50] = 127, @@ -13701,7 +13701,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 38, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 38, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CN][52] = 127, @@ -14133,7 +14133,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 52, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 52, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CN][48] = 127, @@ -14141,7 +14141,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 52, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 52, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CN][50] = 127, @@ -14149,7 +14149,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 50, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 50, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CN][52] = 127, @@ -14581,7 +14581,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][48] = 62, [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, - [2][0][RTW89_IC][48] = 127, + [2][0][RTW89_IC][48] = 62, [2][0][RTW89_KCC][48] = 127, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CN][48] = 127, @@ -14589,7 +14589,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][50] = 62, [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, - [2][0][RTW89_IC][50] = 127, + [2][0][RTW89_IC][50] = 62, [2][0][RTW89_KCC][50] = 127, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CN][50] = 127, @@ -14597,7 +14597,7 @@ const s8 rtw89_8851b_txpwr_lmt_ru_5g_type2[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_FCC][52] = 60, [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, - [2][0][RTW89_IC][52] = 127, + [2][0][RTW89_IC][52] = 60, [2][0][RTW89_KCC][52] = 127, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CN][52] = 127, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 0c76c52ce22c..c28f05bbdccf 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2043,6 +2043,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .enable_bb_rf = rtw89_mac_enable_bb_rf, .disable_bb_rf = rtw89_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852a_bb_reset, .bb_sethw = rtw8852a_bb_sethw, .read_rf = rtw89_phy_read_rf, @@ -2078,6 +2079,12 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852a_btc_set_rfe, .btc_init_cfg = rtw8852a_btc_init_cfg, @@ -2130,7 +2137,9 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .support_chanctx_num = 1, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = false, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index de887a35f3fb..18ed372ed5cd 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -988,7 +988,7 @@ static void rtw8852b_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; @@ -1086,7 +1086,7 @@ next: static void rtw8852b_set_rxsc_rpl_comp(struct rtw89_dev *rtwdev, enum rtw89_subband subband) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 band = rtw89_subband_to_bb_gain_band(subband); u32 val; @@ -2468,6 +2468,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .enable_bb_rf = rtw8852b_mac_enable_bb_rf, .disable_bb_rf = rtw8852b_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852b_bb_reset, .bb_sethw = rtw8852b_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, @@ -2503,6 +2504,12 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx, .resume_sch_tx = rtw89_mac_resume_sch_tx, .h2c_dctl_sec_cam = NULL, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852b_btc_set_rfe, .btc_init_cfg = rtw8852b_btc_init_cfg, @@ -2564,7 +2571,9 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .support_chanctx_num = 0, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), - .support_bw160 = false, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), .support_unii4 = true, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c index d2ce16e98bac..07945d06dc59 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_table.c @@ -16936,7 +16936,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][8] = 52, [0][0][1][0][RTW89_WW][10] = 52, [0][0][1][0][RTW89_WW][12] = 52, - [0][0][1][0][RTW89_WW][14] = 1, + [0][0][1][0][RTW89_WW][14] = 52, [0][0][1][0][RTW89_WW][15] = 52, [0][0][1][0][RTW89_WW][17] = 52, [0][0][1][0][RTW89_WW][19] = 52, @@ -16954,10 +16954,10 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_WW][42] = 28, [0][0][1][0][RTW89_WW][44] = 28, [0][0][1][0][RTW89_WW][46] = 28, - [0][0][1][0][RTW89_WW][48] = 78, - [0][0][1][0][RTW89_WW][50] = 78, - [0][0][1][0][RTW89_WW][52] = 78, - [0][1][1][0][RTW89_WW][0] = 1, + [0][0][1][0][RTW89_WW][48] = 76, + [0][0][1][0][RTW89_WW][50] = 76, + [0][0][1][0][RTW89_WW][52] = 76, + [0][1][1][0][RTW89_WW][0] = 30, [0][1][1][0][RTW89_WW][2] = 32, [0][1][1][0][RTW89_WW][4] = 30, [0][1][1][0][RTW89_WW][6] = 30, @@ -16982,9 +16982,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_WW][42] = 16, [0][1][1][0][RTW89_WW][44] = 16, [0][1][1][0][RTW89_WW][46] = 16, - [0][1][1][0][RTW89_WW][48] = 56, - [0][1][1][0][RTW89_WW][50] = 56, - [0][1][1][0][RTW89_WW][52] = 56, + [0][1][1][0][RTW89_WW][48] = 50, + [0][1][1][0][RTW89_WW][50] = 50, + [0][1][1][0][RTW89_WW][52] = 50, [0][0][2][0][RTW89_WW][0] = 42, [0][0][2][0][RTW89_WW][2] = 42, [0][0][2][0][RTW89_WW][4] = 42, @@ -17038,9 +17038,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_WW][42] = 16, [0][1][2][0][RTW89_WW][44] = 16, [0][1][2][0][RTW89_WW][46] = 16, - [0][1][2][0][RTW89_WW][48] = 58, - [0][1][2][0][RTW89_WW][50] = 58, - [0][1][2][0][RTW89_WW][52] = 58, + [0][1][2][0][RTW89_WW][48] = 50, + [0][1][2][0][RTW89_WW][50] = 52, + [0][1][2][0][RTW89_WW][52] = 52, [0][1][2][1][RTW89_WW][0] = 14, [0][1][2][1][RTW89_WW][2] = 14, [0][1][2][1][RTW89_WW][4] = 14, @@ -17066,9 +17066,9 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_WW][42] = 4, [0][1][2][1][RTW89_WW][44] = 4, [0][1][2][1][RTW89_WW][46] = 4, - [0][1][2][1][RTW89_WW][48] = 58, - [0][1][2][1][RTW89_WW][50] = 58, - [0][1][2][1][RTW89_WW][52] = 58, + [0][1][2][1][RTW89_WW][48] = 50, + [0][1][2][1][RTW89_WW][50] = 52, + [0][1][2][1][RTW89_WW][52] = 52, [1][0][2][0][RTW89_WW][1] = 42, [1][0][2][0][RTW89_WW][5] = 42, [1][0][2][0][RTW89_WW][9] = 52, @@ -17095,8 +17095,8 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_WW][36] = 50, [1][1][2][0][RTW89_WW][39] = 16, [1][1][2][0][RTW89_WW][43] = 16, - [1][1][2][0][RTW89_WW][47] = 68, - [1][1][2][0][RTW89_WW][51] = 66, + [1][1][2][0][RTW89_WW][47] = 62, + [1][1][2][0][RTW89_WW][51] = 62, [1][1][2][1][RTW89_WW][1] = 16, [1][1][2][1][RTW89_WW][5] = 16, [1][1][2][1][RTW89_WW][9] = 28, @@ -17109,8 +17109,8 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_WW][36] = 36, [1][1][2][1][RTW89_WW][39] = 4, [1][1][2][1][RTW89_WW][43] = 4, - [1][1][2][1][RTW89_WW][47] = 68, - [1][1][2][1][RTW89_WW][51] = 66, + [1][1][2][1][RTW89_WW][47] = 62, + [1][1][2][1][RTW89_WW][51] = 62, [2][0][2][0][RTW89_WW][3] = 42, [2][0][2][0][RTW89_WW][11] = 52, [2][0][2][0][RTW89_WW][18] = 52, @@ -17227,7 +17227,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_MEXICO][14] = 78, [0][0][1][0][RTW89_CN][14] = 58, [0][0][1][0][RTW89_QATAR][14] = 58, - [0][0][1][0][RTW89_UK][14] = 1, + [0][0][1][0][RTW89_UK][14] = 58, [0][0][1][0][RTW89_FCC][15] = 76, [0][0][1][0][RTW89_ETSI][15] = 58, [0][0][1][0][RTW89_MKK][15] = 76, @@ -17435,7 +17435,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][48] = 78, [0][0][1][0][RTW89_ETSI][48] = 127, [0][0][1][0][RTW89_MKK][48] = 127, - [0][0][1][0][RTW89_IC][48] = 127, + [0][0][1][0][RTW89_IC][48] = 76, [0][0][1][0][RTW89_KCC][48] = 127, [0][0][1][0][RTW89_ACMA][48] = 127, [0][0][1][0][RTW89_CHILE][48] = 127, @@ -17447,7 +17447,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][50] = 78, [0][0][1][0][RTW89_ETSI][50] = 127, [0][0][1][0][RTW89_MKK][50] = 127, - [0][0][1][0][RTW89_IC][50] = 127, + [0][0][1][0][RTW89_IC][50] = 76, [0][0][1][0][RTW89_KCC][50] = 127, [0][0][1][0][RTW89_ACMA][50] = 127, [0][0][1][0][RTW89_CHILE][50] = 127, @@ -17459,7 +17459,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][1][0][RTW89_FCC][52] = 78, [0][0][1][0][RTW89_ETSI][52] = 127, [0][0][1][0][RTW89_MKK][52] = 127, - [0][0][1][0][RTW89_IC][52] = 127, + [0][0][1][0][RTW89_IC][52] = 76, [0][0][1][0][RTW89_KCC][52] = 127, [0][0][1][0][RTW89_ACMA][52] = 127, [0][0][1][0][RTW89_CHILE][52] = 127, @@ -17479,7 +17479,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_MEXICO][0] = 50, [0][1][1][0][RTW89_CN][0] = 46, [0][1][1][0][RTW89_QATAR][0] = 46, - [0][1][1][0][RTW89_UK][0] = 1, + [0][1][1][0][RTW89_UK][0] = 46, [0][1][1][0][RTW89_FCC][2] = 68, [0][1][1][0][RTW89_ETSI][2] = 46, [0][1][1][0][RTW89_MKK][2] = 48, @@ -17771,7 +17771,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][48] = 56, [0][1][1][0][RTW89_ETSI][48] = 127, [0][1][1][0][RTW89_MKK][48] = 127, - [0][1][1][0][RTW89_IC][48] = 127, + [0][1][1][0][RTW89_IC][48] = 50, [0][1][1][0][RTW89_KCC][48] = 127, [0][1][1][0][RTW89_ACMA][48] = 127, [0][1][1][0][RTW89_CHILE][48] = 127, @@ -17783,7 +17783,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][50] = 56, [0][1][1][0][RTW89_ETSI][50] = 127, [0][1][1][0][RTW89_MKK][50] = 127, - [0][1][1][0][RTW89_IC][50] = 127, + [0][1][1][0][RTW89_IC][50] = 50, [0][1][1][0][RTW89_KCC][50] = 127, [0][1][1][0][RTW89_ACMA][50] = 127, [0][1][1][0][RTW89_CHILE][50] = 127, @@ -17795,7 +17795,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][1][0][RTW89_FCC][52] = 56, [0][1][1][0][RTW89_ETSI][52] = 127, [0][1][1][0][RTW89_MKK][52] = 127, - [0][1][1][0][RTW89_IC][52] = 127, + [0][1][1][0][RTW89_IC][52] = 50, [0][1][1][0][RTW89_KCC][52] = 127, [0][1][1][0][RTW89_ACMA][52] = 127, [0][1][1][0][RTW89_CHILE][52] = 127, @@ -18107,7 +18107,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][48] = 78, [0][0][2][0][RTW89_ETSI][48] = 127, [0][0][2][0][RTW89_MKK][48] = 127, - [0][0][2][0][RTW89_IC][48] = 127, + [0][0][2][0][RTW89_IC][48] = 78, [0][0][2][0][RTW89_KCC][48] = 127, [0][0][2][0][RTW89_ACMA][48] = 127, [0][0][2][0][RTW89_CHILE][48] = 127, @@ -18119,7 +18119,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][50] = 78, [0][0][2][0][RTW89_ETSI][50] = 127, [0][0][2][0][RTW89_MKK][50] = 127, - [0][0][2][0][RTW89_IC][50] = 127, + [0][0][2][0][RTW89_IC][50] = 78, [0][0][2][0][RTW89_KCC][50] = 127, [0][0][2][0][RTW89_ACMA][50] = 127, [0][0][2][0][RTW89_CHILE][50] = 127, @@ -18131,7 +18131,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][0][2][0][RTW89_FCC][52] = 78, [0][0][2][0][RTW89_ETSI][52] = 127, [0][0][2][0][RTW89_MKK][52] = 127, - [0][0][2][0][RTW89_IC][52] = 127, + [0][0][2][0][RTW89_IC][52] = 78, [0][0][2][0][RTW89_KCC][52] = 127, [0][0][2][0][RTW89_ACMA][52] = 127, [0][0][2][0][RTW89_CHILE][52] = 127, @@ -18443,7 +18443,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][48] = 58, [0][1][2][0][RTW89_ETSI][48] = 127, [0][1][2][0][RTW89_MKK][48] = 127, - [0][1][2][0][RTW89_IC][48] = 127, + [0][1][2][0][RTW89_IC][48] = 50, [0][1][2][0][RTW89_KCC][48] = 127, [0][1][2][0][RTW89_ACMA][48] = 127, [0][1][2][0][RTW89_CHILE][48] = 127, @@ -18455,7 +18455,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][50] = 58, [0][1][2][0][RTW89_ETSI][50] = 127, [0][1][2][0][RTW89_MKK][50] = 127, - [0][1][2][0][RTW89_IC][50] = 127, + [0][1][2][0][RTW89_IC][50] = 52, [0][1][2][0][RTW89_KCC][50] = 127, [0][1][2][0][RTW89_ACMA][50] = 127, [0][1][2][0][RTW89_CHILE][50] = 127, @@ -18467,7 +18467,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][0][RTW89_FCC][52] = 58, [0][1][2][0][RTW89_ETSI][52] = 127, [0][1][2][0][RTW89_MKK][52] = 127, - [0][1][2][0][RTW89_IC][52] = 127, + [0][1][2][0][RTW89_IC][52] = 52, [0][1][2][0][RTW89_KCC][52] = 127, [0][1][2][0][RTW89_ACMA][52] = 127, [0][1][2][0][RTW89_CHILE][52] = 127, @@ -18779,7 +18779,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][48] = 58, [0][1][2][1][RTW89_ETSI][48] = 127, [0][1][2][1][RTW89_MKK][48] = 127, - [0][1][2][1][RTW89_IC][48] = 127, + [0][1][2][1][RTW89_IC][48] = 50, [0][1][2][1][RTW89_KCC][48] = 127, [0][1][2][1][RTW89_ACMA][48] = 127, [0][1][2][1][RTW89_CHILE][48] = 127, @@ -18791,7 +18791,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][50] = 58, [0][1][2][1][RTW89_ETSI][50] = 127, [0][1][2][1][RTW89_MKK][50] = 127, - [0][1][2][1][RTW89_IC][50] = 127, + [0][1][2][1][RTW89_IC][50] = 52, [0][1][2][1][RTW89_KCC][50] = 127, [0][1][2][1][RTW89_ACMA][50] = 127, [0][1][2][1][RTW89_CHILE][50] = 127, @@ -18803,7 +18803,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [0][1][2][1][RTW89_FCC][52] = 58, [0][1][2][1][RTW89_ETSI][52] = 127, [0][1][2][1][RTW89_MKK][52] = 127, - [0][1][2][1][RTW89_IC][52] = 127, + [0][1][2][1][RTW89_IC][52] = 52, [0][1][2][1][RTW89_KCC][52] = 127, [0][1][2][1][RTW89_ACMA][52] = 127, [0][1][2][1][RTW89_CHILE][52] = 127, @@ -18959,7 +18959,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][47] = 78, [1][0][2][0][RTW89_ETSI][47] = 127, [1][0][2][0][RTW89_MKK][47] = 127, - [1][0][2][0][RTW89_IC][47] = 127, + [1][0][2][0][RTW89_IC][47] = 78, [1][0][2][0][RTW89_KCC][47] = 127, [1][0][2][0][RTW89_ACMA][47] = 127, [1][0][2][0][RTW89_CHILE][47] = 127, @@ -18971,7 +18971,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][0][2][0][RTW89_FCC][51] = 70, [1][0][2][0][RTW89_ETSI][51] = 127, [1][0][2][0][RTW89_MKK][51] = 127, - [1][0][2][0][RTW89_IC][51] = 127, + [1][0][2][0][RTW89_IC][51] = 78, [1][0][2][0][RTW89_KCC][51] = 127, [1][0][2][0][RTW89_ACMA][51] = 127, [1][0][2][0][RTW89_CHILE][51] = 127, @@ -19127,7 +19127,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_FCC][47] = 68, [1][1][2][0][RTW89_ETSI][47] = 127, [1][1][2][0][RTW89_MKK][47] = 127, - [1][1][2][0][RTW89_IC][47] = 127, + [1][1][2][0][RTW89_IC][47] = 62, [1][1][2][0][RTW89_KCC][47] = 127, [1][1][2][0][RTW89_ACMA][47] = 127, [1][1][2][0][RTW89_CHILE][47] = 127, @@ -19139,7 +19139,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][0][RTW89_FCC][51] = 66, [1][1][2][0][RTW89_ETSI][51] = 127, [1][1][2][0][RTW89_MKK][51] = 127, - [1][1][2][0][RTW89_IC][51] = 127, + [1][1][2][0][RTW89_IC][51] = 62, [1][1][2][0][RTW89_KCC][51] = 127, [1][1][2][0][RTW89_ACMA][51] = 127, [1][1][2][0][RTW89_CHILE][51] = 127, @@ -19295,7 +19295,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_FCC][47] = 68, [1][1][2][1][RTW89_ETSI][47] = 127, [1][1][2][1][RTW89_MKK][47] = 127, - [1][1][2][1][RTW89_IC][47] = 127, + [1][1][2][1][RTW89_IC][47] = 62, [1][1][2][1][RTW89_KCC][47] = 127, [1][1][2][1][RTW89_ACMA][47] = 127, [1][1][2][1][RTW89_CHILE][47] = 127, @@ -19307,7 +19307,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [1][1][2][1][RTW89_FCC][51] = 66, [1][1][2][1][RTW89_ETSI][51] = 127, [1][1][2][1][RTW89_MKK][51] = 127, - [1][1][2][1][RTW89_IC][51] = 127, + [1][1][2][1][RTW89_IC][51] = 62, [1][1][2][1][RTW89_KCC][51] = 127, [1][1][2][1][RTW89_ACMA][51] = 127, [1][1][2][1][RTW89_CHILE][51] = 127, @@ -19391,7 +19391,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][0][2][0][RTW89_FCC][49] = 64, [2][0][2][0][RTW89_ETSI][49] = 127, [2][0][2][0][RTW89_MKK][49] = 127, - [2][0][2][0][RTW89_IC][49] = 127, + [2][0][2][0][RTW89_IC][49] = 74, [2][0][2][0][RTW89_KCC][49] = 127, [2][0][2][0][RTW89_ACMA][49] = 127, [2][0][2][0][RTW89_CHILE][49] = 127, @@ -19475,7 +19475,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][0][RTW89_FCC][49] = 58, [2][1][2][0][RTW89_ETSI][49] = 127, [2][1][2][0][RTW89_MKK][49] = 127, - [2][1][2][0][RTW89_IC][49] = 127, + [2][1][2][0][RTW89_IC][49] = 66, [2][1][2][0][RTW89_KCC][49] = 127, [2][1][2][0][RTW89_ACMA][49] = 127, [2][1][2][0][RTW89_CHILE][49] = 127, @@ -19559,7 +19559,7 @@ const s8 rtw89_8852b_txpwr_lmt_5g[RTW89_5G_BW_NUM][RTW89_NTX_NUM] [2][1][2][1][RTW89_FCC][49] = 58, [2][1][2][1][RTW89_ETSI][49] = 127, [2][1][2][1][RTW89_MKK][49] = 127, - [2][1][2][1][RTW89_IC][49] = 127, + [2][1][2][1][RTW89_IC][49] = 66, [2][1][2][1][RTW89_KCC][49] = 127, [2][1][2][1][RTW89_ACMA][49] = 127, [2][1][2][1][RTW89_CHILE][49] = 127, @@ -20723,9 +20723,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_WW][42] = 14, [0][1][RTW89_WW][44] = 14, [0][1][RTW89_WW][46] = 14, - [0][1][RTW89_WW][48] = 20, - [0][1][RTW89_WW][50] = 20, - [0][1][RTW89_WW][52] = 20, + [0][1][RTW89_WW][48] = 16, + [0][1][RTW89_WW][50] = 16, + [0][1][RTW89_WW][52] = 16, [1][0][RTW89_WW][0] = 34, [1][0][RTW89_WW][2] = 34, [1][0][RTW89_WW][4] = 34, @@ -20779,9 +20779,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_WW][42] = 16, [1][1][RTW89_WW][44] = 16, [1][1][RTW89_WW][46] = 16, - [1][1][RTW89_WW][48] = 32, - [1][1][RTW89_WW][50] = 32, - [1][1][RTW89_WW][52] = 32, + [1][1][RTW89_WW][48] = 28, + [1][1][RTW89_WW][50] = 30, + [1][1][RTW89_WW][52] = 30, [2][0][RTW89_WW][0] = 44, [2][0][RTW89_WW][2] = 44, [2][0][RTW89_WW][4] = 44, @@ -20835,9 +20835,9 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_WW][42] = 16, [2][1][RTW89_WW][44] = 16, [2][1][RTW89_WW][46] = 16, - [2][1][RTW89_WW][48] = 44, - [2][1][RTW89_WW][50] = 44, - [2][1][RTW89_WW][52] = 44, + [2][1][RTW89_WW][48] = 40, + [2][1][RTW89_WW][50] = 40, + [2][1][RTW89_WW][52] = 40, [0][0][RTW89_FCC][0] = 52, [0][0][RTW89_ETSI][0] = 24, [0][0][RTW89_MKK][0] = 26, @@ -21141,7 +21141,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][48] = 32, [0][0][RTW89_ETSI][48] = 127, [0][0][RTW89_MKK][48] = 127, - [0][0][RTW89_IC][48] = 127, + [0][0][RTW89_IC][48] = 42, [0][0][RTW89_KCC][48] = 127, [0][0][RTW89_ACMA][48] = 127, [0][0][RTW89_CHILE][48] = 127, @@ -21153,7 +21153,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][50] = 32, [0][0][RTW89_ETSI][50] = 127, [0][0][RTW89_MKK][50] = 127, - [0][0][RTW89_IC][50] = 127, + [0][0][RTW89_IC][50] = 42, [0][0][RTW89_KCC][50] = 127, [0][0][RTW89_ACMA][50] = 127, [0][0][RTW89_CHILE][50] = 127, @@ -21165,7 +21165,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][0][RTW89_FCC][52] = 32, [0][0][RTW89_ETSI][52] = 127, [0][0][RTW89_MKK][52] = 127, - [0][0][RTW89_IC][52] = 127, + [0][0][RTW89_IC][52] = 40, [0][0][RTW89_KCC][52] = 127, [0][0][RTW89_ACMA][52] = 127, [0][0][RTW89_CHILE][52] = 127, @@ -21477,7 +21477,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][48] = 20, [0][1][RTW89_ETSI][48] = 127, [0][1][RTW89_MKK][48] = 127, - [0][1][RTW89_IC][48] = 127, + [0][1][RTW89_IC][48] = 16, [0][1][RTW89_KCC][48] = 127, [0][1][RTW89_ACMA][48] = 127, [0][1][RTW89_CHILE][48] = 127, @@ -21489,7 +21489,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][50] = 20, [0][1][RTW89_ETSI][50] = 127, [0][1][RTW89_MKK][50] = 127, - [0][1][RTW89_IC][50] = 127, + [0][1][RTW89_IC][50] = 16, [0][1][RTW89_KCC][50] = 127, [0][1][RTW89_ACMA][50] = 127, [0][1][RTW89_CHILE][50] = 127, @@ -21501,7 +21501,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [0][1][RTW89_FCC][52] = 20, [0][1][RTW89_ETSI][52] = 127, [0][1][RTW89_MKK][52] = 127, - [0][1][RTW89_IC][52] = 127, + [0][1][RTW89_IC][52] = 16, [0][1][RTW89_KCC][52] = 127, [0][1][RTW89_ACMA][52] = 127, [0][1][RTW89_CHILE][52] = 127, @@ -21813,7 +21813,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][48] = 44, [1][0][RTW89_ETSI][48] = 127, [1][0][RTW89_MKK][48] = 127, - [1][0][RTW89_IC][48] = 127, + [1][0][RTW89_IC][48] = 54, [1][0][RTW89_KCC][48] = 127, [1][0][RTW89_ACMA][48] = 127, [1][0][RTW89_CHILE][48] = 127, @@ -21825,7 +21825,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][50] = 44, [1][0][RTW89_ETSI][50] = 127, [1][0][RTW89_MKK][50] = 127, - [1][0][RTW89_IC][50] = 127, + [1][0][RTW89_IC][50] = 54, [1][0][RTW89_KCC][50] = 127, [1][0][RTW89_ACMA][50] = 127, [1][0][RTW89_CHILE][50] = 127, @@ -21837,7 +21837,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][0][RTW89_FCC][52] = 44, [1][0][RTW89_ETSI][52] = 127, [1][0][RTW89_MKK][52] = 127, - [1][0][RTW89_IC][52] = 127, + [1][0][RTW89_IC][52] = 52, [1][0][RTW89_KCC][52] = 127, [1][0][RTW89_ACMA][52] = 127, [1][0][RTW89_CHILE][52] = 127, @@ -22149,7 +22149,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][48] = 32, [1][1][RTW89_ETSI][48] = 127, [1][1][RTW89_MKK][48] = 127, - [1][1][RTW89_IC][48] = 127, + [1][1][RTW89_IC][48] = 28, [1][1][RTW89_KCC][48] = 127, [1][1][RTW89_ACMA][48] = 127, [1][1][RTW89_CHILE][48] = 127, @@ -22161,7 +22161,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][50] = 32, [1][1][RTW89_ETSI][50] = 127, [1][1][RTW89_MKK][50] = 127, - [1][1][RTW89_IC][50] = 127, + [1][1][RTW89_IC][50] = 30, [1][1][RTW89_KCC][50] = 127, [1][1][RTW89_ACMA][50] = 127, [1][1][RTW89_CHILE][50] = 127, @@ -22173,7 +22173,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [1][1][RTW89_FCC][52] = 32, [1][1][RTW89_ETSI][52] = 127, [1][1][RTW89_MKK][52] = 127, - [1][1][RTW89_IC][52] = 127, + [1][1][RTW89_IC][52] = 30, [1][1][RTW89_KCC][52] = 127, [1][1][RTW89_ACMA][52] = 127, [1][1][RTW89_CHILE][52] = 127, @@ -22486,7 +22486,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][48] = 127, [2][0][RTW89_MKK][48] = 127, [2][0][RTW89_IC][48] = 127, - [2][0][RTW89_KCC][48] = 127, + [2][0][RTW89_KCC][48] = 66, [2][0][RTW89_ACMA][48] = 127, [2][0][RTW89_CHILE][48] = 127, [2][0][RTW89_UKRAINE][48] = 127, @@ -22498,7 +22498,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][50] = 127, [2][0][RTW89_MKK][50] = 127, [2][0][RTW89_IC][50] = 127, - [2][0][RTW89_KCC][50] = 127, + [2][0][RTW89_KCC][50] = 66, [2][0][RTW89_ACMA][50] = 127, [2][0][RTW89_CHILE][50] = 127, [2][0][RTW89_UKRAINE][50] = 127, @@ -22510,7 +22510,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][0][RTW89_ETSI][52] = 127, [2][0][RTW89_MKK][52] = 127, [2][0][RTW89_IC][52] = 127, - [2][0][RTW89_KCC][52] = 127, + [2][0][RTW89_KCC][52] = 66, [2][0][RTW89_ACMA][52] = 127, [2][0][RTW89_CHILE][52] = 127, [2][0][RTW89_UKRAINE][52] = 127, @@ -22821,7 +22821,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][48] = 44, [2][1][RTW89_ETSI][48] = 127, [2][1][RTW89_MKK][48] = 127, - [2][1][RTW89_IC][48] = 127, + [2][1][RTW89_IC][48] = 40, [2][1][RTW89_KCC][48] = 127, [2][1][RTW89_ACMA][48] = 127, [2][1][RTW89_CHILE][48] = 127, @@ -22833,7 +22833,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][50] = 44, [2][1][RTW89_ETSI][50] = 127, [2][1][RTW89_MKK][50] = 127, - [2][1][RTW89_IC][50] = 127, + [2][1][RTW89_IC][50] = 40, [2][1][RTW89_KCC][50] = 127, [2][1][RTW89_ACMA][50] = 127, [2][1][RTW89_CHILE][50] = 127, @@ -22845,7 +22845,7 @@ const s8 rtw89_8852b_txpwr_lmt_ru_5g[RTW89_RU_NUM][RTW89_NTX_NUM] [2][1][RTW89_FCC][52] = 44, [2][1][RTW89_ETSI][52] = 127, [2][1][RTW89_MKK][52] = 127, - [2][1][RTW89_IC][52] = 127, + [2][1][RTW89_IC][52] = 40, [2][1][RTW89_KCC][52] = 127, [2][1][RTW89_ACMA][52] = 127, [2][1][RTW89_CHILE][52] = 127, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 8618d0204f66..431acfaba89b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -842,7 +842,7 @@ static void rtw8852c_set_gain_error(struct rtw89_dev *rtwdev, enum rtw89_subband subband, enum rtw89_rf_path path) { - const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain; + const struct rtw89_phy_bb_gain_info *gain = &rtwdev->bb_gain.ax; u8 gain_band = rtw89_subband_to_bb_gain_band(subband); s32 val; u32 reg; @@ -2813,6 +2813,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .enable_bb_rf = rtw8852c_mac_enable_bb_rf, .disable_bb_rf = rtw8852c_mac_disable_bb_rf, .bb_preinit = NULL, + .bb_postinit = NULL, .bb_reset = rtw8852c_bb_reset, .bb_sethw = rtw8852c_bb_sethw, .read_rf = rtw89_phy_read_rf_v1, @@ -2848,6 +2849,12 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, .resume_sch_tx = rtw89_mac_resume_sch_tx_v1, .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v1, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, + .h2c_ampdu_cmac_tbl = NULL, + .h2c_default_dmac_tbl = NULL, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam, .btc_set_rfe = rtw8852c_btc_set_rfe, .btc_init_cfg = rtw8852c_btc_init_cfg, @@ -2902,7 +2909,10 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), - .support_bw160 = true, + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), .support_unii4 = true, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = true, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 0e7300cc6d9e..f34e2a8bff07 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -63,6 +63,31 @@ static const struct rtw89_dle_mem rtw8922a_dle_mem_pcie[] = { NULL}, }; +static const u32 rtw8922a_h2c_regs[RTW89_H2CREG_MAX] = { + R_BE_H2CREG_DATA0, R_BE_H2CREG_DATA1, R_BE_H2CREG_DATA2, + R_BE_H2CREG_DATA3 +}; + +static const u32 rtw8922a_c2h_regs[RTW89_H2CREG_MAX] = { + R_BE_C2HREG_DATA0, R_BE_C2HREG_DATA1, R_BE_C2HREG_DATA2, + R_BE_C2HREG_DATA3 +}; + +static const struct rtw89_page_regs rtw8922a_page_regs = { + .hci_fc_ctrl = R_BE_HCI_FC_CTRL, + .ch_page_ctrl = R_BE_CH_PAGE_CTRL, + .ach_page_ctrl = R_BE_CH0_PAGE_CTRL, + .ach_page_info = R_BE_CH0_PAGE_INFO, + .pub_page_info3 = R_BE_PUB_PAGE_INFO3, + .pub_page_ctrl1 = R_BE_PUB_PAGE_CTRL1, + .pub_page_ctrl2 = R_BE_PUB_PAGE_CTRL2, + .pub_page_info1 = R_BE_PUB_PAGE_INFO1, + .pub_page_info2 = R_BE_PUB_PAGE_INFO2, + .wp_page_ctrl1 = R_BE_WP_PAGE_CTRL1, + .wp_page_ctrl2 = R_BE_WP_PAGE_CTRL2, + .wp_page_info1 = R_BE_WP_PAGE_INFO1, +}; + static const struct rtw89_reg_imr rtw8922a_imr_dmac_regs[] = { {R_BE_DISP_HOST_IMR, B_BE_DISP_HOST_IMR_CLR, B_BE_DISP_HOST_IMR_SET}, {R_BE_DISP_CPU_IMR, B_BE_DISP_CPU_IMR_CLR, B_BE_DISP_CPU_IMR_SET}, @@ -119,6 +144,51 @@ static const struct rtw89_imr_table rtw8922a_imr_cmac_table = { .n_regs = ARRAY_SIZE(rtw8922a_imr_cmac_regs), }; +static const struct rtw89_rrsr_cfgs rtw8922a_rrsr_cfgs = { + .ref_rate = {R_BE_TRXPTCL_RESP_1, B_BE_WMAC_RESP_REF_RATE_SEL, 0}, + .rsc = {R_BE_PTCL_RRSR1, B_BE_RSC_MASK, 2}, +}; + +static const struct rtw89_dig_regs rtw8922a_dig_regs = { + .seg0_pd_reg = R_SEG0R_PD_V2, + .pd_lower_bound_mask = B_SEG0R_PD_LOWER_BOUND_MSK, + .pd_spatial_reuse_en = B_SEG0R_PD_SPATIAL_REUSE_EN_MSK_V1, + .bmode_pd_reg = R_BMODE_PDTH_EN_V2, + .bmode_cca_rssi_limit_en = B_BMODE_PDTH_LIMIT_EN_MSK_V1, + .bmode_pd_lower_bound_reg = R_BMODE_PDTH_V2, + .bmode_rssi_nocca_low_th_mask = B_BMODE_PDTH_LOWER_BOUND_MSK_V1, + .p0_lna_init = {R_PATH0_LNA_INIT_V1, B_PATH0_LNA_INIT_IDX_MSK}, + .p1_lna_init = {R_PATH1_LNA_INIT_V1, B_PATH1_LNA_INIT_IDX_MSK}, + .p0_tia_init = {R_PATH0_TIA_INIT_V1, B_PATH0_TIA_INIT_IDX_MSK_V1}, + .p1_tia_init = {R_PATH1_TIA_INIT_V1, B_PATH1_TIA_INIT_IDX_MSK_V1}, + .p0_rxb_init = {R_PATH0_RXB_INIT_V1, B_PATH0_RXB_INIT_IDX_MSK_V1}, + .p1_rxb_init = {R_PATH1_RXB_INIT_V1, B_PATH1_RXB_INIT_IDX_MSK_V1}, + .p0_p20_pagcugc_en = {R_PATH0_P20_FOLLOW_BY_PAGCUGC_V3, + B_PATH0_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p0_s20_pagcugc_en = {R_PATH0_S20_FOLLOW_BY_PAGCUGC_V3, + B_PATH0_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_p20_pagcugc_en = {R_PATH1_P20_FOLLOW_BY_PAGCUGC_V3, + B_PATH1_P20_FOLLOW_BY_PAGCUGC_EN_MSK}, + .p1_s20_pagcugc_en = {R_PATH1_S20_FOLLOW_BY_PAGCUGC_V3, + B_PATH1_S20_FOLLOW_BY_PAGCUGC_EN_MSK}, +}; + +static const struct rtw89_edcca_regs rtw8922a_edcca_regs = { + .edcca_level = R_SEG0R_EDCCA_LVL_BE, + .edcca_mask = B_EDCCA_LVL_MSK0, + .edcca_p_mask = B_EDCCA_LVL_MSK1, + .ppdu_level = R_SEG0R_PPDU_LVL_BE, + .ppdu_mask = B_EDCCA_LVL_MSK1, + .rpt_a = R_EDCCA_RPT_A_BE, + .rpt_b = R_EDCCA_RPT_B_BE, + .rpt_sel = R_EDCCA_RPT_SEL_BE, + .rpt_sel_mask = B_EDCCA_RPT_SEL_MSK, + .rpt_sel_be = R_EDCCA_RPTREG_SEL_BE, + .rpt_sel_be_mask = B_EDCCA_RPTREG_SEL_BE_MSK, + .tx_collision_t2r_st = R_TX_COLLISION_T2R_ST_BE, + .tx_collision_t2r_st_mask = B_TX_COLLISION_T2R_ST_BE_M, +}; + static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_SYS] = {.offset = 0x00000, .size = 0x310}, [RTW89_EFUSE_BLOCK_RF] = {.offset = 0x10000, .size = 0x240}, @@ -130,6 +200,36 @@ static const struct rtw89_efuse_block_cfg rtw8922a_efuse_blocks[] = { [RTW89_EFUSE_BLOCK_ADIE] = {.offset = 0x70000, .size = 0x10}, }; +static void rtw8922a_ctrl_btg_bt_rx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_SHARE_A, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BTG_PATH_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_SHARE_B, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BTG_PATH_B, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x20, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x30, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_BT_SHARE, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_BT_SG0, 0x2, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, + 0x1, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_SHARE_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BTG_PATH_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_SHARE_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BTG_PATH_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x1a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_PMAC_GNT, B_PMAC_GNT_P1, 0xc, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_ANT_CHBW, B_ANT_BT_SHARE, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FC0INV_SBW, B_RX_BT_SG0, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_GNT_BT_WGT_EN, B_GNT_BT_WGT_EN, + 0x0, phy_idx); + } +} + static int rtw8922a_pwr_on_func(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -574,6 +674,32 @@ static void rtw8922a_phycap_parsing_pa_bias_trim(struct rtw89_dev *rtwdev, } } +static void rtw8922a_pa_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pabias_2g, pabias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] no PG, do nothing\n"); + + return; + } + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pabias_2g = FIELD_GET(GENMASK(3, 0), info->pa_bias_trim[i]); + pabias_5g = FIELD_GET(GENMASK(7, 4), info->pa_bias_trim[i]); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PA_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pabias_2g, pabias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXG_V1, pabias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASA_TXA_V1, pabias_5g); + } +} + static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, u8 *phycap_map) { @@ -591,6 +717,31 @@ static void rtw8922a_phycap_parsing_pad_bias_trim(struct rtw89_dev *rtwdev, } } +static void rtw8922a_pad_bias_trim(struct rtw89_dev *rtwdev) +{ + struct rtw89_power_trim_info *info = &rtwdev->pwr_trim; + u8 pad_bias_2g, pad_bias_5g; + u8 i; + + if (!info->pg_pa_bias_trim) { + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] no PG, do nothing\n"); + return; + } + + for (i = 0; i < RF_PATH_NUM_8922A; i++) { + pad_bias_2g = u8_get_bits(info->pad_bias_trim[i], GENMASK(3, 0)); + pad_bias_5g = u8_get_bits(info->pad_bias_trim[i], GENMASK(7, 4)); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, + "[PAD_BIAS][TRIM] path=%d 2G=0x%x 5G=0x%x\n", + i, pad_bias_2g, pad_bias_5g); + + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXG_V1, pad_bias_2g); + rtw89_write_rf(rtwdev, i, RR_BIASA, RR_BIASD_TXA_V1, pad_bias_5g); + } +} + static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) { rtw8922a_phycap_parsing_thermal_trim(rtwdev, phycap_map); @@ -600,6 +751,522 @@ static int rtw8922a_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) return 0; } +static void rtw8922a_power_trim(struct rtw89_dev *rtwdev) +{ + rtw8922a_pa_bias_trim(rtwdev); + rtw8922a_pad_bias_trim(rtwdev); +} + +struct rtw8922a_bb_gain { + u32 gain_g[BB_PATH_NUM_8922A]; + u32 gain_a[BB_PATH_NUM_8922A]; + u32 gain_g_mask; + u32 gain_a_mask; +}; + +static const struct rtw89_reg_def rpl_comp_bw160[RTW89_BW20_SC_160M] = { + { .addr = 0x41E8, .mask = 0xFF00}, + { .addr = 0x41E8, .mask = 0xFF0000}, + { .addr = 0x41E8, .mask = 0xFF000000}, + { .addr = 0x41EC, .mask = 0xFF}, + { .addr = 0x41EC, .mask = 0xFF00}, + { .addr = 0x41EC, .mask = 0xFF0000}, + { .addr = 0x41EC, .mask = 0xFF000000}, + { .addr = 0x41F0, .mask = 0xFF} +}; + +static const struct rtw89_reg_def rpl_comp_bw80[RTW89_BW20_SC_80M] = { + { .addr = 0x41F4, .mask = 0xFF}, + { .addr = 0x41F4, .mask = 0xFF00}, + { .addr = 0x41F4, .mask = 0xFF0000}, + { .addr = 0x41F4, .mask = 0xFF000000} +}; + +static const struct rtw89_reg_def rpl_comp_bw40[RTW89_BW20_SC_40M] = { + { .addr = 0x41F0, .mask = 0xFF0000}, + { .addr = 0x41F0, .mask = 0xFF000000} +}; + +static const struct rtw89_reg_def rpl_comp_bw20[RTW89_BW20_SC_20M] = { + { .addr = 0x41F0, .mask = 0xFF00} +}; + +static const struct rtw8922a_bb_gain bb_gain_lna[LNA_GAIN_NUM] = { + { .gain_g = {0x409c, 0x449c}, .gain_a = {0x406C, 0x446C}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x409c, 0x449c}, .gain_a = {0x406C, 0x446C}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a0, 0x44a0}, .gain_a = {0x4070, 0x4470}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x40a0, 0x44a0}, .gain_a = {0x4070, 0x4470}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a4, 0x44a4}, .gain_a = {0x4074, 0x4474}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, + { .gain_g = {0x40a4, 0x44a4}, .gain_a = {0x4074, 0x4474}, + .gain_g_mask = 0xFF000000, .gain_a_mask = 0xFF0000}, + { .gain_g = {0x40a8, 0x44a8}, .gain_a = {0x4078, 0x4478}, + .gain_g_mask = 0xFF00, .gain_a_mask = 0xFF}, +}; + +static const struct rtw8922a_bb_gain bb_gain_tia[TIA_GAIN_NUM] = { + { .gain_g = {0x4054, 0x4454}, .gain_a = {0x4054, 0x4454}, + .gain_g_mask = 0x7FC0000, .gain_a_mask = 0x1FF}, + { .gain_g = {0x4058, 0x4458}, .gain_a = {0x4054, 0x4454}, + .gain_g_mask = 0x1FF, .gain_a_mask = 0x3FE00 }, +}; + +struct rtw8922a_bb_gain_bypass { + u32 gain_g[BB_PATH_NUM_8922A]; + u32 gain_a[BB_PATH_NUM_8922A]; + u32 gain_mask_g; + u32 gain_mask_a; +}; + +static void rtw8922a_set_rpl_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type); + u32 reg_path_ofst = 0; + u32 mask; + s32 val; + u32 reg; + int i; + + if (path == RF_PATH_B) + reg_path_ofst = 0x400; + + for (i = 0; i < RTW89_BW20_SC_160M; i++) { + reg = rpl_comp_bw160[i].addr | reg_path_ofst; + mask = rpl_comp_bw160[i].mask; + val = gain->rpl_ofst_160[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_80M; i++) { + reg = rpl_comp_bw80[i].addr | reg_path_ofst; + mask = rpl_comp_bw80[i].mask; + val = gain->rpl_ofst_80[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_40M; i++) { + reg = rpl_comp_bw40[i].addr | reg_path_ofst; + mask = rpl_comp_bw40[i].mask; + val = gain->rpl_ofst_40[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < RTW89_BW20_SC_20M; i++) { + reg = rpl_comp_bw20[i].addr | reg_path_ofst; + mask = rpl_comp_bw20[i].mask; + val = gain->rpl_ofst_20[gain_band][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } +} + +static void rtw8922a_set_lna_tia_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_phy_bb_gain_info_be *gain = &rtwdev->bb_gain.be; + u8 gain_band = rtw89_subband_to_gain_band_be(chan->subband_type); + enum rtw89_phy_bb_bw_be bw_type; + s32 val; + u32 reg; + u32 mask; + int i; + + bw_type = chan->band_width <= RTW89_CHANNEL_WIDTH_40 ? + RTW89_BB_BW_20_40 : RTW89_BB_BW_80_160_320; + + for (i = 0; i < LNA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_gain_lna[i].gain_g[path]; + mask = bb_gain_lna[i].gain_g_mask; + } else { + reg = bb_gain_lna[i].gain_a[path]; + mask = bb_gain_lna[i].gain_a_mask; + } + val = gain->lna_gain[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } + + for (i = 0; i < TIA_GAIN_NUM; i++) { + if (chan->band_type == RTW89_BAND_2G) { + reg = bb_gain_tia[i].gain_g[path]; + mask = bb_gain_tia[i].gain_g_mask; + } else { + reg = bb_gain_tia[i].gain_a[path]; + mask = bb_gain_tia[i].gain_a_mask; + } + val = gain->tia_gain[gain_band][bw_type][path][i]; + rtw89_phy_write32_idx(rtwdev, reg, mask, val, phy_idx); + } +} + +static void rtw8922a_set_gain(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_rf_path path, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_lna_tia_gain(rtwdev, chan, path, phy_idx); + rtw8922a_set_rpl_gain(rtwdev, chan, path, phy_idx); +} + +static void rtw8922a_ctrl_ch(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_gain(rtwdev, chan, RF_PATH_A, phy_idx); + rtw8922a_set_gain(rtwdev, chan, RF_PATH_B, phy_idx); +} + +static void rtw8922a_ctrl_afe_dac(struct rtw89_dev *rtwdev, enum rtw89_bandwidth bw, + enum rtw89_rf_path path) +{ + u32 cr_ofst = 0x0; + + if (path == RF_PATH_B) + cr_ofst = 0x100; + + switch (bw) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + case RTW89_CHANNEL_WIDTH_40: + case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_AFEDAC0 + cr_ofst, B_AFEDAC0, 0xE); + rtw89_phy_write32_mask(rtwdev, R_AFEDAC1 + cr_ofst, B_AFEDAC1, 0x7); + break; + case RTW89_CHANNEL_WIDTH_160: + rtw89_phy_write32_mask(rtwdev, R_AFEDAC0 + cr_ofst, B_AFEDAC0, 0xD); + rtw89_phy_write32_mask(rtwdev, R_AFEDAC1 + cr_ofst, B_AFEDAC1, 0x6); + break; + default: + break; + } +} + +static const struct rtw89_reg2_def bb_mcu0_init_reg[] = { + {0x6990, 0x00000000}, + {0x6994, 0x00000000}, + {0x6998, 0x00000000}, + {0x6820, 0xFFFFFFFE}, + {0x6800, 0xC0000FFE}, + {0x6808, 0x76543210}, + {0x6814, 0xBFBFB000}, + {0x6818, 0x0478C009}, + {0x6800, 0xC0000FFF}, + {0x6820, 0xFFFFFFFF}, +}; + +static const struct rtw89_reg2_def bb_mcu1_init_reg[] = { + {0x6990, 0x00000000}, + {0x6994, 0x00000000}, + {0x6998, 0x00000000}, + {0x6820, 0xFFFFFFFE}, + {0x6800, 0xC0000FFE}, + {0x6808, 0x76543210}, + {0x6814, 0xBFBFB000}, + {0x6818, 0x0478C009}, + {0x6800, 0xC0000FFF}, + {0x6820, 0xFFFFFFFF}, +}; + +static void rtw8922a_bbmcu_cr_init(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_reg2_def *reg; + int size; + int i; + + if (phy_idx == RTW89_PHY_0) { + reg = bb_mcu0_init_reg; + size = ARRAY_SIZE(bb_mcu0_init_reg); + } else { + reg = bb_mcu1_init_reg; + size = ARRAY_SIZE(bb_mcu1_init_reg); + } + + for (i = 0; i < size; i++, reg++) + rtw89_bbmcu_write32(rtwdev, reg->addr, reg->data, phy_idx); +} + +static const u32 dmac_sys_mask[2] = {B_BE_DMAC_BB_PHY0_MASK, B_BE_DMAC_BB_PHY1_MASK}; +static const u32 bbrst_mask[2] = {B_BE_FEN_BBPLAT_RSTB, B_BE_FEN_BB1PLAT_RSTB}; +static const u32 glbrst_mask[2] = {B_BE_FEN_BB_IP_RSTN, B_BE_FEN_BB1_IP_RSTN}; +static const u32 mcu_bootrdy_mask[2] = {B_BE_BOOT_RDY0, B_BE_BOOT_RDY1}; + +static void rtw8922a_bb_preinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + u32 rdy = 0; + + if (phy_idx == RTW89_PHY_1) + rdy = 1; + + rtw89_write32_mask(rtwdev, R_BE_DMAC_SYS_CR32B, dmac_sys_mask[phy_idx], 0x7FF9); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x0); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx], 0x0); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, glbrst_mask[phy_idx], 0x1); + rtw89_write32_mask(rtwdev, R_BE_FEN_RST_ENABLE, mcu_bootrdy_mask[phy_idx], rdy); + rtw89_write32_mask(rtwdev, R_BE_MEM_PWR_CTRL, B_BE_MEM_BBMCU0_DS_V1, 0); + + fsleep(1); + rtw8922a_bbmcu_cr_init(rtwdev, phy_idx); +} + +static void rtw8922a_bb_postinit(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + if (phy_idx == RTW89_PHY_0) + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, mcu_bootrdy_mask[phy_idx]); + rtw89_write32_set(rtwdev, R_BE_FEN_RST_ENABLE, bbrst_mask[phy_idx]); + + rtw89_phy_write32_set(rtwdev, R_BBCLK, B_CLK_640M); + rtw89_phy_write32_clr(rtwdev, R_TXSCALE, B_TXFCTR_EN); + rtw89_phy_set_phy_regs(rtwdev, R_TXFCTR, B_TXFCTR_THD, 0x200); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_EHT_RATE_TH, 0xA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE, B_HE_RATE_TH, 0xA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE2, B_HT_VHT_TH, 0xAAA); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE, B_EHT_MCS14, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE2, B_EHT_MCS15, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_EHTTB_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_HEERSU_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_HEMU_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE3, B_TB_EN, 0x0); + rtw89_phy_set_phy_regs(rtwdev, R_SU_PUNC, B_SU_PUNC_EN, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE5, B_HWGEN_EN, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_BEDGE5, B_PWROFST_COMP, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_AB, B_BY_SLOPE, 0x1); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_A, B_MGA_AEND, 0xe0); + rtw89_phy_set_phy_regs(rtwdev, R_MAG_AB, B_MAG_AB, 0xe0c000); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_SLOPE_A, 0x3FE0); + rtw89_phy_set_phy_regs(rtwdev, R_SLOPE, B_SLOPE_B, 0x3FE0); + rtw89_phy_set_phy_regs(rtwdev, R_SC_CORNER, B_SC_CORNER, 0x200); + rtw89_phy_write32_idx(rtwdev, R_UDP_COEEF, B_UDP_COEEF, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_UDP_COEEF, B_UDP_COEEF, 0x1, phy_idx); +} + +static void rtw8922a_bb_reset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ +} + +static int rtw8922a_ctrl_mlo(struct rtw89_dev *rtwdev, enum rtw89_mlo_dbcc_mode mode) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, RTW89_SUB_ENTITY_0); + + if (mode == MLO_1_PLUS_1_1RF || mode == DBCC_LEGACY) { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x1); + rtw89_phy_write32_mask(rtwdev, R_DBCC_FA, B_DBCC_FA, 0x0); + } else if (mode == MLO_2_PLUS_0_1RF || mode == MLO_0_PLUS_2_1RF || + mode == MLO_DBCC_NOT_SUPPORT) { + rtw89_phy_write32_mask(rtwdev, R_DBCC, B_DBCC_EN, 0x0); + rtw89_phy_write32_mask(rtwdev, R_DBCC_FA, B_DBCC_FA, 0x1); + } else { + return -EOPNOTSUPP; + } + + if (mode == MLO_2_PLUS_0_1RF) { + rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_A); + rtw8922a_ctrl_afe_dac(rtwdev, chan->band_width, RF_PATH_B); + } else { + rtw89_warn(rtwdev, "unsupported MLO mode %d\n", mode); + } + + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x6180); + + if (mode == MLO_2_PLUS_0_1RF) { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xBBAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xABA9); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEBA9); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEAA9); + } else if (mode == MLO_0_PLUS_2_1RF) { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xBBAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xAFFF); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEFFF); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0xEEFF); + } else if ((mode == MLO_1_PLUS_1_1RF) || (mode == DBCC_LEGACY)) { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x7BAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x3BAB); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x3AAB); + } else { + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x180); + rtw89_phy_write32_mask(rtwdev, R_EMLSR, B_EMLSR_PARM, 0x0); + } + + return 0; +} + +static void rtw8922a_bb_sethw(struct rtw89_dev *rtwdev) +{ + u32 reg; + + rtw89_phy_write32_clr(rtwdev, R_EN_SND_WO_NDP, B_EN_SND_WO_NDP); + rtw89_phy_write32_clr(rtwdev, R_EN_SND_WO_NDP_C1, B_EN_SND_WO_NDP); + + rtw89_write32_mask(rtwdev, R_BE_PWR_BOOST, B_BE_PWR_CTRL_SEL, 0); + if (rtwdev->dbcc_en) { + reg = rtw89_mac_reg_by_idx(rtwdev, R_BE_PWR_BOOST, RTW89_MAC_1); + rtw89_write32_mask(rtwdev, reg, B_BE_PWR_CTRL_SEL, 0); + } + + rtw8922a_ctrl_mlo(rtwdev, rtwdev->mlo_dbcc_mode); +} + +static void rtw8922a_set_channel_bb(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_ctrl_ch(rtwdev, chan, phy_idx); +} + +static void rtw8922a_set_channel(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_mac_idx mac_idx, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_channel_bb(rtwdev, chan, phy_idx); +} + +static void rtw8922a_set_txpwr_ref(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + s16 ref_ofdm = 0; + s16 ref_cck = 0; + + rtw89_debug(rtwdev, RTW89_DBG_TXPWR, "[TXPWR] set txpwr reference\n"); + + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL, + B_BE_PWR_REF_CTRL_OFDM, ref_ofdm); + rtw89_mac_txpwr_write32_mask(rtwdev, phy_idx, R_BE_PWR_REF_CTRL, + B_BE_PWR_REF_CTRL_CCK, ref_cck); +} + +static void rtw8922a_bb_tx_triangular(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + u8 ctrl = en ? 0x1 : 0x0; + + rtw89_phy_write32_idx(rtwdev, R_BEDGE3, B_BEDGE_CFG, ctrl, phy_idx); +} + +static void rtw8922a_set_tx_shape(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_rfe_parms *rfe_parms = rtwdev->rfe_parms; + const struct rtw89_tx_shape *tx_shape = &rfe_parms->tx_shape; + u8 tx_shape_idx; + u8 band, regd; + + band = chan->band_type; + regd = rtw89_regd_get(rtwdev, band); + tx_shape_idx = (*tx_shape->lmt)[band][RTW89_RS_OFDM][regd]; + + if (tx_shape_idx == 0) + rtw8922a_bb_tx_triangular(rtwdev, false, phy_idx); + else + rtw8922a_bb_tx_triangular(rtwdev, true, phy_idx); +} + +static void rtw8922a_set_txpwr(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan, + enum rtw89_phy_idx phy_idx) +{ + rtw89_phy_set_txpwr_byrate(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_offset(rtwdev, chan, phy_idx); + rtw8922a_set_tx_shape(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit(rtwdev, chan, phy_idx); + rtw89_phy_set_txpwr_limit_ru(rtwdev, chan, phy_idx); +} + +static void rtw8922a_set_txpwr_ctrl(struct rtw89_dev *rtwdev, + enum rtw89_phy_idx phy_idx) +{ + rtw8922a_set_txpwr_ref(rtwdev, phy_idx); +} + +static void rtw8922a_ctrl_nbtg_bt_tx(struct rtw89_dev *rtwdev, bool en, + enum rtw89_phy_idx phy_idx) +{ + if (en) { + rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A, + 0xf, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA0_A, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA1_A, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_IBADC_A, + 0x34, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_LNA_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x34, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x3, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B, + 0xf, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x80, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_IBADC_B, + 0x34, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_LNA_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x34, phy_idx); + } else { + rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_A, B_FORCE_FIR_A, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_A, B_RXBY_WBADC_A, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_A, B_BT_RXBY_WBADC_A, + 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_A, B_BT_TRK_OFF_A, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB_A, B_OP1DB_A, 0x1a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA0_A, 0x2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_OP1DB1_A, B_TIA1_A, 0x2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_IBADC_A, + 0x26, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_A, B_BACKOFF_LNA_A, + 0x1e, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BKOFF_A, B_BKOFF_IBADC_A, 0x26, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_FORCE_FIR_B, B_FORCE_FIR_B, 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_RXBY_WBADC_B, B_RXBY_WBADC_B, + 0x0, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_RXBY_WBADC_B, B_BT_RXBY_WBADC_B, + 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BT_SHARE_B, B_BT_TRK_OFF_B, 0x1, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_OP, B_LNA6, 0x20, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA0_B, 0x30, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_LNA_TIA, B_TIA1_B, 0x2a, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_IBADC_B, + 0x26, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BACKOFF_B, B_BACKOFF_LNA_B, + 0x1e, phy_idx); + rtw89_phy_write32_idx(rtwdev, R_BKOFF_B, B_BKOFF_IBADC_B, 0x26, phy_idx); + } +} + +static int rtw8922a_mac_enable_bb_rf(struct rtw89_dev *rtwdev) +{ + rtw89_write8_set(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_FEN_BBPLAT_RSTB | B_BE_FEN_BB_IP_RSTN); + rtw89_write32(rtwdev, R_BE_DMAC_SYS_CR32B, 0x7FF97FF9); + + return 0; +} + +static int rtw8922a_mac_disable_bb_rf(struct rtw89_dev *rtwdev) +{ + rtw89_write8_clr(rtwdev, R_BE_FEN_RST_ENABLE, + B_BE_FEN_BBPLAT_RSTB | B_BE_FEN_BB_IP_RSTN); + + return 0; +} + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -610,10 +1277,31 @@ static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { #endif static const struct rtw89_chip_ops rtw8922a_chip_ops = { + .enable_bb_rf = rtw8922a_mac_enable_bb_rf, + .disable_bb_rf = rtw8922a_mac_disable_bb_rf, + .bb_preinit = rtw8922a_bb_preinit, + .bb_postinit = rtw8922a_bb_postinit, + .bb_reset = rtw8922a_bb_reset, + .bb_sethw = rtw8922a_bb_sethw, + .set_channel = rtw8922a_set_channel, .read_efuse = rtw8922a_read_efuse, .read_phycap = rtw8922a_read_phycap, + .power_trim = rtw8922a_power_trim, + .set_txpwr = rtw8922a_set_txpwr, + .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, + .init_txpwr_unit = NULL, + .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, + .ctrl_nbtg_bt_tx = rtw8922a_ctrl_nbtg_bt_tx, + .set_txpwr_ul_tb_offset = NULL, .pwr_on_func = rtw8922a_pwr_on_func, .pwr_off_func = rtw8922a_pwr_off_func, + .h2c_dctl_sec_cam = rtw89_fw_h2c_dctl_sec_cam_v2, + .h2c_default_cmac_tbl = rtw89_fw_h2c_default_cmac_tbl_g7, + .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, + .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, + .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, + .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, + .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, }; const struct rtw89_chip_info rtw8922a_chip_info = { @@ -650,11 +1338,16 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, .dig_table = NULL, + .dig_regs = &rtw8922a_dig_regs, .tssi_dbw_table = NULL, .support_chanctx_num = 1, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ) | BIT(NL80211_BAND_6GHZ), + .support_bandwidths = BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), .support_unii4 = true, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, @@ -665,7 +1358,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .acam_num = 128, .bcam_num = 20, .scam_num = 32, - .bacam_num = 8, + .bacam_num = 24, .bacam_dynamic_num = 8, .bacam_ver = RTW89_BACAM_V1, .ppdu_max_usr = 16, @@ -683,10 +1376,18 @@ const struct rtw89_chip_info rtw8922a_chip_info = { BIT(RTW89_PS_MODE_CLK_GATED) | BIT(RTW89_PS_MODE_PWR_GATED), .low_power_hci_modes = 0, + .h2c_cctl_func_id = H2C_FUNC_MAC_CCTLINFO_UD_G7, .hci_func_en_addr = R_BE_HCI_FUNC_EN, .h2c_desc_size = sizeof(struct rtw89_rxdesc_short_v2), .txwd_body_size = sizeof(struct rtw89_txwd_body_v2), .txwd_info_size = sizeof(struct rtw89_txwd_info_v2), + .h2c_ctrl_reg = R_BE_H2CREG_CTRL, + .h2c_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_H2C_DEQ_CNT_MASK >> 8}, + .h2c_regs = rtw8922a_h2c_regs, + .c2h_ctrl_reg = R_BE_C2HREG_CTRL, + .c2h_counter_reg = {R_BE_UDM1 + 1, B_BE_UDM1_HALMAC_C2H_ENQ_CNT_MASK >> 8}, + .c2h_regs = rtw8922a_c2h_regs, + .page_regs = &rtw8922a_page_regs, .cfo_src_fd = true, .cfo_hw_comp = true, .dcfo_comp = NULL, @@ -694,9 +1395,11 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .imr_info = NULL, .imr_dmac_table = &rtw8922a_imr_dmac_table, .imr_cmac_table = &rtw8922a_imr_cmac_table, + .rrsr_cfgs = &rtw8922a_rrsr_cfgs, .bss_clr_vld = {R_BSS_CLR_VLD_V2, B_BSS_CLR_VLD0_V2}, .bss_clr_map_reg = R_BSS_CLR_MAP_V2, .dma_ch_mask = 0, + .edcca_regs = &rtw8922a_edcca_regs, #ifdef CONFIG_PM .wowlan_stub = &rtw_wowlan_stub_8922a, #endif diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 5c7ca36c09b6..4c17936795b6 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -519,7 +519,7 @@ static int rtw89_wow_swap_fw(struct rtw89_dev *rtwdev, bool wow) return ret; } - ret = rtw89_fw_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); + ret = rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, wow_vif, wow_sta); if (ret) { rtw89_warn(rtwdev, "failed to send h2c assoc cmac tbl\n"); return ret; diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 5dd5f188e14f..604541dcb320 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -155,6 +155,18 @@ config PTP_1588_CLOCK_IDTCM To compile this driver as a module, choose M here: the module will be called ptp_clockmatrix. +config PTP_1588_CLOCK_FC3W + tristate "RENESAS FemtoClock3 Wireless as PTP clock" + depends on PTP_1588_CLOCK && I2C + default n + help + This driver adds support for using Renesas FemtoClock3 Wireless + as a PTP clock. This clock is only useful if your time stamping + MAC is connected to the RENESAS chip. + + To compile this driver as a module, choose M here: the module + will be called ptp_fc3. + config PTP_1588_CLOCK_MOCK tristate "Mock-up PTP clock" depends on PTP_1588_CLOCK diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile index dea0cebd2303..68bf02078053 100644 --- a/drivers/ptp/Makefile +++ b/drivers/ptp/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PTP_1588_CLOCK_QORIQ) += ptp-qoriq.o ptp-qoriq-y += ptp_qoriq.o ptp-qoriq-$(CONFIG_DEBUG_FS) += ptp_qoriq_debugfs.o obj-$(CONFIG_PTP_1588_CLOCK_IDTCM) += ptp_clockmatrix.o +obj-$(CONFIG_PTP_1588_CLOCK_FC3W) += ptp_fc3.o obj-$(CONFIG_PTP_1588_CLOCK_IDT82P33) += ptp_idt82p33.o obj-$(CONFIG_PTP_1588_CLOCK_MOCK) += ptp_mock.o obj-$(CONFIG_PTP_1588_CLOCK_VMW) += ptp_vmw.o diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 15b804ba4868..3aaf1a3430c5 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -44,18 +44,31 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue, struct ptp_clock_event *src) { struct ptp_extts_event *dst; + struct timespec64 offset_ts; unsigned long flags; s64 seconds; u32 remainder; - seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + if (src->type == PTP_CLOCK_EXTTS) { + seconds = div_u64_rem(src->timestamp, 1000000000, &remainder); + } else if (src->type == PTP_CLOCK_EXTOFF) { + offset_ts = ns_to_timespec64(src->offset); + seconds = offset_ts.tv_sec; + remainder = offset_ts.tv_nsec; + } else { + WARN(1, "%s: unknown type %d\n", __func__, src->type); + return; + } spin_lock_irqsave(&queue->lock, flags); dst = &queue->buf[queue->tail]; dst->index = src->index; + dst->flags = PTP_EXTTS_EVENT_VALID; dst->t.sec = seconds; dst->t.nsec = remainder; + if (src->type == PTP_CLOCK_EXTOFF) + dst->flags |= PTP_EXT_OFFSET; /* Both WRITE_ONCE() are paired with READ_ONCE() in queue_cnt() */ if (!queue_free(queue)) @@ -417,6 +430,7 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event) break; case PTP_CLOCK_EXTTS: + case PTP_CLOCK_EXTOFF: /* Enqueue timestamp on selected queues */ spin_lock_irqsave(&ptp->tsevqs_lock, flags); list_for_each_entry(tsevq, &ptp->tsevqs, qlist) { diff --git a/drivers/ptp/ptp_fc3.c b/drivers/ptp/ptp_fc3.c new file mode 100644 index 000000000000..0e2286ba088a --- /dev/null +++ b/drivers/ptp/ptp_fc3.c @@ -0,0 +1,1016 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PTP hardware clock driver for the FemtoClock3 family of timing and + * synchronization devices. + * + * Copyright (C) 2023 Integrated Device Technology, Inc., a Renesas Company. + */ +#include <linux/firmware.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/timekeeping.h> +#include <linux/string.h> +#include <linux/of.h> +#include <linux/bitfield.h> +#include <linux/mfd/rsmu.h> +#include <linux/mfd/idtRC38xxx_reg.h> +#include <asm/unaligned.h> + +#include "ptp_private.h" +#include "ptp_fc3.h" + +MODULE_DESCRIPTION("Driver for IDT FemtoClock3(TM) family"); +MODULE_AUTHOR("IDT support-1588 <IDT-support-1588@lm.renesas.com>"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); + +/* + * The name of the firmware file to be loaded + * over-rides any automatic selection + */ +static char *firmware; +module_param(firmware, charp, 0); + +static s64 ns2counters(struct idtfc3 *idtfc3, s64 nsec, u32 *sub_ns) +{ + s64 sync; + s32 rem; + + if (likely(nsec >= 0)) { + sync = div_u64_rem(nsec, idtfc3->ns_per_sync, &rem); + *sub_ns = rem; + } else { + sync = -div_u64_rem(-nsec - 1, idtfc3->ns_per_sync, &rem) - 1; + *sub_ns = idtfc3->ns_per_sync - rem - 1; + } + + return sync * idtfc3->ns_per_sync; +} + +static s64 tdc_meas2offset(struct idtfc3 *idtfc3, u64 meas_read) +{ + s64 coarse, fine; + + fine = sign_extend64(FIELD_GET(FINE_MEAS_MASK, meas_read), 12); + coarse = sign_extend64(FIELD_GET(COARSE_MEAS_MASK, meas_read), (39 - 13)); + + fine = div64_s64(fine * NSEC_PER_SEC, idtfc3->tdc_apll_freq * 62LL); + coarse = div64_s64(coarse * NSEC_PER_SEC, idtfc3->time_ref_freq); + + return coarse + fine; +} + +static s64 tdc_offset2phase(struct idtfc3 *idtfc3, s64 offset_ns) +{ + if (offset_ns > idtfc3->ns_per_sync / 2) + offset_ns -= idtfc3->ns_per_sync; + + return offset_ns * idtfc3->tdc_offset_sign; +} + +static int idtfc3_set_lpf_mode(struct idtfc3 *idtfc3, u8 mode) +{ + int err; + + if (mode >= LPF_INVALID) + return -EINVAL; + + if (idtfc3->lpf_mode == mode) + return 0; + + err = regmap_bulk_write(idtfc3->regmap, LPF_MODE_CNFG, &mode, sizeof(mode)); + if (err) + return err; + + idtfc3->lpf_mode = mode; + + return 0; +} + +static int idtfc3_enable_lpf(struct idtfc3 *idtfc3, bool enable) +{ + u8 val; + int err; + + err = regmap_bulk_read(idtfc3->regmap, LPF_CTRL, &val, sizeof(val)); + if (err) + return err; + + if (enable == true) + val |= LPF_EN; + else + val &= ~LPF_EN; + + return regmap_bulk_write(idtfc3->regmap, LPF_CTRL, &val, sizeof(val)); +} + +static int idtfc3_get_time_ref_freq(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + u8 time_ref_div; + u8 time_clk_div; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_MEAS_DIV_CNFG, buf, sizeof(buf)); + if (err) + return err; + time_ref_div = FIELD_GET(TIME_REF_DIV_MASK, get_unaligned_le32(buf)) + 1; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_COUNT, buf, 1); + if (err) + return err; + time_clk_div = (buf[0] & TIME_CLOCK_COUNT_MASK) + 1; + idtfc3->time_ref_freq = idtfc3->hw_param.time_clk_freq * + time_clk_div / time_ref_div; + + return 0; +} + +static int idtfc3_get_tdc_offset_sign(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + u32 val; + u8 sig1, sig2; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_TDC_FANOUT_CNFG, buf, sizeof(buf)); + if (err) + return err; + + val = get_unaligned_le32(buf); + if ((val & TIME_SYNC_TO_TDC_EN) != TIME_SYNC_TO_TDC_EN) { + dev_err(idtfc3->dev, "TIME_SYNC_TO_TDC_EN is off !!!"); + return -EINVAL; + } + + sig1 = FIELD_GET(SIG1_MUX_SEL_MASK, val); + sig2 = FIELD_GET(SIG2_MUX_SEL_MASK, val); + + if ((sig1 == sig2) || ((sig1 != TIME_SYNC) && (sig2 != TIME_SYNC))) { + dev_err(idtfc3->dev, "Invalid tdc_mux_sel sig1=%d sig2=%d", sig1, sig2); + return -EINVAL; + } else if (sig1 == TIME_SYNC) { + idtfc3->tdc_offset_sign = 1; + } else if (sig2 == TIME_SYNC) { + idtfc3->tdc_offset_sign = -1; + } + + return 0; +} + +static int idtfc3_lpf_bw(struct idtfc3 *idtfc3, u8 shift, u8 mult) +{ + u8 val = FIELD_PREP(LPF_BW_SHIFT, shift) | FIELD_PREP(LPF_BW_MULT, mult); + + return regmap_bulk_write(idtfc3->regmap, LPF_BW_CNFG, &val, sizeof(val)); +} + +static int idtfc3_enable_tdc(struct idtfc3 *idtfc3, bool enable, u8 meas_mode) +{ + int err; + u8 val = 0; + + /* Disable TDC first */ + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CTRL, &val, sizeof(val)); + if (err) + return err; + + if (enable == false) + return idtfc3_lpf_bw(idtfc3, LPF_BW_SHIFT_DEFAULT, LPF_BW_MULT_DEFAULT); + + if (meas_mode >= MEAS_MODE_INVALID) + return -EINVAL; + + /* Change TDC meas mode */ + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CNFG, + &meas_mode, sizeof(meas_mode)); + if (err) + return err; + + /* Enable TDC */ + val = TDC_MEAS_EN; + if (meas_mode == CONTINUOUS) + val |= TDC_MEAS_START; + err = regmap_bulk_write(idtfc3->regmap, TIME_CLOCK_MEAS_CTRL, &val, sizeof(val)); + if (err) + return err; + + return idtfc3_lpf_bw(idtfc3, LPF_BW_SHIFT_1PPS, LPF_BW_MULT_DEFAULT); +} + +static bool get_tdc_meas(struct idtfc3 *idtfc3, s64 *offset_ns) +{ + bool valid = false; + u8 buf[9]; + u8 val; + int err; + + while (true) { + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_STS, + &val, sizeof(val)); + if (err) + return false; + + if (val & FIFO_EMPTY) + break; + + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_READ_REQ, + &buf, sizeof(buf)); + if (err) + return false; + + valid = true; + } + + if (valid) + *offset_ns = tdc_meas2offset(idtfc3, get_unaligned_le64(&buf[1])); + + return valid; +} + +static int check_tdc_fifo_overrun(struct idtfc3 *idtfc3) +{ + u8 val; + int err; + + /* Check if FIFO is overrun */ + err = regmap_bulk_read(idtfc3->regmap, TDC_FIFO_STS, &val, sizeof(val)); + if (err) + return err; + + if (!(val & FIFO_FULL)) + return 0; + + dev_warn(idtfc3->dev, "TDC FIFO overrun !!!"); + + err = idtfc3_enable_tdc(idtfc3, true, CONTINUOUS); + if (err) + return err; + + return 0; +} + +static int get_tdc_meas_continuous(struct idtfc3 *idtfc3) +{ + int err; + s64 offset_ns; + struct ptp_clock_event event; + + err = check_tdc_fifo_overrun(idtfc3); + if (err) + return err; + + if (get_tdc_meas(idtfc3, &offset_ns) && offset_ns >= 0) { + event.index = 0; + event.offset = tdc_offset2phase(idtfc3, offset_ns); + event.type = PTP_CLOCK_EXTOFF; + ptp_clock_event(idtfc3->ptp_clock, &event); + } + + return 0; +} + +static int idtfc3_read_subcounter(struct idtfc3 *idtfc3) +{ + u8 buf[5] = {0}; + int err; + + err = regmap_bulk_read(idtfc3->regmap, TOD_COUNTER_READ_REQ, + &buf, sizeof(buf)); + if (err) + return err; + + /* sync_counter_value is [31:82] and sub_sync_counter_value is [0:30] */ + return get_unaligned_le32(&buf[1]) & SUB_SYNC_COUNTER_MASK; +} + +static int idtfc3_tod_update_is_done(struct idtfc3 *idtfc3) +{ + int err; + u8 req; + + err = read_poll_timeout_atomic(regmap_bulk_read, err, !req, USEC_PER_MSEC, + idtfc3->tc_write_timeout, true, idtfc3->regmap, + TOD_SYNC_LOAD_REQ_CTRL, &req, 1); + if (err) + dev_err(idtfc3->dev, "TOD counter write timeout !!!"); + + return err; +} + +static int idtfc3_write_subcounter(struct idtfc3 *idtfc3, u32 counter) +{ + u8 buf[18] = {0}; + int err; + + /* sync_counter_value is [31:82] and sub_sync_counter_value is [0:30] */ + put_unaligned_le32(counter & SUB_SYNC_COUNTER_MASK, &buf[0]); + + buf[16] = SUB_SYNC_LOAD_ENABLE | SYNC_LOAD_ENABLE; + buf[17] = SYNC_LOAD_REQ; + + err = regmap_bulk_write(idtfc3->regmap, TOD_SYNC_LOAD_VAL_CTRL, + &buf, sizeof(buf)); + if (err) + return err; + + return idtfc3_tod_update_is_done(idtfc3); +} + +static int idtfc3_timecounter_update(struct idtfc3 *idtfc3, u32 counter, s64 ns) +{ + int err; + + err = idtfc3_write_subcounter(idtfc3, counter); + if (err) + return err; + + /* Update time counter */ + idtfc3->ns = ns; + idtfc3->last_counter = counter; + + return 0; +} + +static int idtfc3_timecounter_read(struct idtfc3 *idtfc3) +{ + int now, delta; + + now = idtfc3_read_subcounter(idtfc3); + if (now < 0) + return now; + + /* calculate the delta since the last idtfc3_timecounter_read(): */ + if (now >= idtfc3->last_counter) + delta = now - idtfc3->last_counter; + else + delta = idtfc3->sub_sync_count - idtfc3->last_counter + now; + + /* Update time counter */ + idtfc3->ns += delta * idtfc3->ns_per_counter; + idtfc3->last_counter = now; + + return 0; +} + +static int _idtfc3_gettime(struct idtfc3 *idtfc3, struct timespec64 *ts) +{ + int err; + + err = idtfc3_timecounter_read(idtfc3); + if (err) + return err; + + *ts = ns_to_timespec64(idtfc3->ns); + + return 0; +} + +static int idtfc3_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_gettime(idtfc3, ts); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_settime(struct idtfc3 *idtfc3, const struct timespec64 *ts) +{ + s64 offset_ns, now_ns; + u32 counter, sub_ns; + int now; + + if (timespec64_valid(ts) == false) { + dev_err(idtfc3->dev, "%s: invalid timespec", __func__); + return -EINVAL; + } + + now = idtfc3_read_subcounter(idtfc3); + if (now < 0) + return now; + + offset_ns = (idtfc3->sub_sync_count - now) * idtfc3->ns_per_counter; + now_ns = timespec64_to_ns(ts); + (void)ns2counters(idtfc3, offset_ns + now_ns, &sub_ns); + + counter = sub_ns / idtfc3->ns_per_counter; + return idtfc3_timecounter_update(idtfc3, counter, now_ns); +} + +static int idtfc3_settime(struct ptp_clock_info *ptp, const struct timespec64 *ts) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_settime(idtfc3, ts); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjtime(struct idtfc3 *idtfc3, s64 delta) +{ + /* + * The TOD counter can be synchronously loaded with any value, + * to be loaded on the next Time Sync pulse + */ + s64 sync_ns; + u32 sub_ns; + u32 counter; + + if (idtfc3->ns + delta < 0) { + dev_err(idtfc3->dev, "%lld ns adj is too large", delta); + return -EINVAL; + } + + sync_ns = ns2counters(idtfc3, delta + idtfc3->ns_per_sync, &sub_ns); + + counter = sub_ns / idtfc3->ns_per_counter; + return idtfc3_timecounter_update(idtfc3, counter, idtfc3->ns + sync_ns + + counter * idtfc3->ns_per_counter); +} + +static int idtfc3_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjtime(idtfc3, delta); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjphase(struct idtfc3 *idtfc3, s32 delta) +{ + u8 buf[8] = {0}; + int err; + s64 pcw; + + err = idtfc3_set_lpf_mode(idtfc3, LPF_WP); + if (err) + return err; + + /* + * Phase Control Word unit is: 10^9 / (TDC_APLL_FREQ * 124) + * + * delta * TDC_APLL_FREQ * 124 + * PCW = --------------------------- + * 10^9 + * + */ + pcw = div_s64((s64)delta * idtfc3->tdc_apll_freq * 124, NSEC_PER_SEC); + + put_unaligned_le64(pcw, buf); + + return regmap_bulk_write(idtfc3->regmap, LPF_WR_PHASE_CTRL, buf, sizeof(buf)); +} + +static int idtfc3_adjphase(struct ptp_clock_info *ptp, s32 delta) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjphase(idtfc3, delta); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int _idtfc3_adjfine(struct idtfc3 *idtfc3, long scaled_ppm) +{ + u8 buf[8] = {0}; + int err; + s64 fcw; + + err = idtfc3_set_lpf_mode(idtfc3, LPF_WF); + if (err) + return err; + + /* + * Frequency Control Word unit is: 2^-44 * 10^6 ppm + * + * adjfreq: + * ppb * 2^44 + * FCW = ---------- + * 10^9 + * + * adjfine: + * ppm_16 * 2^28 + * FCW = ------------- + * 10^6 + */ + fcw = scaled_ppm * BIT(28); + fcw = div_s64(fcw, 1000000); + + put_unaligned_le64(fcw, buf); + + return regmap_bulk_write(idtfc3->regmap, LPF_WR_FREQ_CTRL, buf, sizeof(buf)); +} + +static int idtfc3_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err; + + mutex_lock(idtfc3->lock); + err = _idtfc3_adjfine(idtfc3, scaled_ppm); + mutex_unlock(idtfc3->lock); + + return err; +} + +static int idtfc3_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + int err = -EOPNOTSUPP; + + mutex_lock(idtfc3->lock); + switch (rq->type) { + case PTP_CLK_REQ_PEROUT: + if (!on) + err = 0; + /* Only accept a 1-PPS aligned to the second. */ + else if (rq->perout.start.nsec || rq->perout.period.sec != 1 || + rq->perout.period.nsec) + err = -ERANGE; + else + err = 0; + break; + case PTP_CLK_REQ_EXTTS: + if (on) { + /* Only accept requests for external phase offset */ + if ((rq->extts.flags & PTP_EXT_OFFSET) != (PTP_EXT_OFFSET)) + err = -EOPNOTSUPP; + else + err = idtfc3_enable_tdc(idtfc3, true, CONTINUOUS); + } else { + err = idtfc3_enable_tdc(idtfc3, false, MEAS_MODE_INVALID); + } + break; + default: + break; + } + mutex_unlock(idtfc3->lock); + + if (err) + dev_err(idtfc3->dev, "Failed in %s with err %d!", __func__, err); + + return err; +} + +static long idtfc3_aux_work(struct ptp_clock_info *ptp) +{ + struct idtfc3 *idtfc3 = container_of(ptp, struct idtfc3, caps); + static int tdc_get; + + mutex_lock(idtfc3->lock); + tdc_get %= TDC_GET_PERIOD; + if ((tdc_get == 0) || (tdc_get == TDC_GET_PERIOD / 2)) + idtfc3_timecounter_read(idtfc3); + get_tdc_meas_continuous(idtfc3); + tdc_get++; + mutex_unlock(idtfc3->lock); + + return idtfc3->tc_update_period; +} + +static const struct ptp_clock_info idtfc3_caps = { + .owner = THIS_MODULE, + .max_adj = MAX_FFO_PPB, + .n_per_out = 1, + .n_ext_ts = 1, + .adjphase = &idtfc3_adjphase, + .adjfine = &idtfc3_adjfine, + .adjtime = &idtfc3_adjtime, + .gettime64 = &idtfc3_gettime, + .settime64 = &idtfc3_settime, + .enable = &idtfc3_enable, + .do_aux_work = &idtfc3_aux_work, +}; + +static int idtfc3_hw_calibrate(struct idtfc3 *idtfc3) +{ + int err = 0; + u8 val; + + mdelay(10); + /* + * Toggle TDC_DAC_RECAL_REQ: + * (1) set tdc_en to 1 + * (2) set tdc_dac_recal_req to 0 + * (3) set tdc_dac_recal_req to 1 + */ + val = TDC_EN; + err = regmap_bulk_write(idtfc3->regmap, TDC_CTRL, + &val, sizeof(val)); + if (err) + return err; + val = TDC_EN | TDC_DAC_RECAL_REQ; + err = regmap_bulk_write(idtfc3->regmap, TDC_CTRL, + &val, sizeof(val)); + if (err) + return err; + mdelay(10); + + /* + * Toggle APLL_REINIT: + * (1) set apll_reinit to 0 + * (2) set apll_reinit to 1 + */ + val = 0; + err = regmap_bulk_write(idtfc3->regmap, SOFT_RESET_CTRL, + &val, sizeof(val)); + if (err) + return err; + val = APLL_REINIT; + err = regmap_bulk_write(idtfc3->regmap, SOFT_RESET_CTRL, + &val, sizeof(val)); + if (err) + return err; + mdelay(10); + + return err; +} + +static int idtfc3_init_timecounter(struct idtfc3 *idtfc3) +{ + int err; + u32 period_ms; + + period_ms = idtfc3->sub_sync_count * MSEC_PER_SEC / + idtfc3->hw_param.time_clk_freq; + + idtfc3->tc_update_period = msecs_to_jiffies(period_ms / TDC_GET_PERIOD); + idtfc3->tc_write_timeout = period_ms * USEC_PER_MSEC; + + err = idtfc3_timecounter_update(idtfc3, 0, 0); + if (err) + return err; + + err = idtfc3_timecounter_read(idtfc3); + if (err) + return err; + + ptp_schedule_worker(idtfc3->ptp_clock, idtfc3->tc_update_period); + + return 0; +} + +static int idtfc3_get_tdc_apll_freq(struct idtfc3 *idtfc3) +{ + int err; + u8 tdc_fb_div_int; + u8 tdc_ref_div; + struct idtfc3_hw_param *param = &idtfc3->hw_param; + + err = regmap_bulk_read(idtfc3->regmap, TDC_REF_DIV_CNFG, + &tdc_ref_div, sizeof(tdc_ref_div)); + if (err) + return err; + + err = regmap_bulk_read(idtfc3->regmap, TDC_FB_DIV_INT_CNFG, + &tdc_fb_div_int, sizeof(tdc_fb_div_int)); + if (err) + return err; + + tdc_fb_div_int &= TDC_FB_DIV_INT_MASK; + tdc_ref_div &= TDC_REF_DIV_CONFIG_MASK; + + idtfc3->tdc_apll_freq = div_u64(param->xtal_freq * (u64)tdc_fb_div_int, + 1 << tdc_ref_div); + + return 0; +} + +static int idtfc3_get_fod(struct idtfc3 *idtfc3) +{ + int err; + u8 fod; + + err = regmap_bulk_read(idtfc3->regmap, TIME_CLOCK_SRC, &fod, sizeof(fod)); + if (err) + return err; + + switch (fod) { + case 0: + idtfc3->fod_n = FOD_0; + break; + case 1: + idtfc3->fod_n = FOD_1; + break; + case 2: + idtfc3->fod_n = FOD_2; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int idtfc3_get_sync_count(struct idtfc3 *idtfc3) +{ + int err; + u8 buf[4]; + + err = regmap_bulk_read(idtfc3->regmap, SUB_SYNC_GEN_CNFG, buf, sizeof(buf)); + if (err) + return err; + + idtfc3->sub_sync_count = (get_unaligned_le32(buf) & SUB_SYNC_COUNTER_MASK) + 1; + idtfc3->ns_per_counter = NSEC_PER_SEC / idtfc3->hw_param.time_clk_freq; + idtfc3->ns_per_sync = idtfc3->sub_sync_count * idtfc3->ns_per_counter; + + return 0; +} + +static int idtfc3_setup_hw_param(struct idtfc3 *idtfc3) +{ + int err; + + err = idtfc3_get_fod(idtfc3); + if (err) + return err; + + err = idtfc3_get_sync_count(idtfc3); + if (err) + return err; + + err = idtfc3_get_time_ref_freq(idtfc3); + if (err) + return err; + + return idtfc3_get_tdc_apll_freq(idtfc3); +} + +static int idtfc3_configure_hw(struct idtfc3 *idtfc3) +{ + int err = 0; + + err = idtfc3_hw_calibrate(idtfc3); + if (err) + return err; + + err = idtfc3_enable_lpf(idtfc3, true); + if (err) + return err; + + err = idtfc3_enable_tdc(idtfc3, false, MEAS_MODE_INVALID); + if (err) + return err; + + err = idtfc3_get_tdc_offset_sign(idtfc3); + if (err) + return err; + + return idtfc3_setup_hw_param(idtfc3); +} + +static int idtfc3_set_overhead(struct idtfc3 *idtfc3) +{ + s64 current_ns = 0; + s64 lowest_ns = 0; + int err; + u8 i; + ktime_t start; + ktime_t stop; + ktime_t diff; + + char buf[18] = {0}; + + for (i = 0; i < 5; i++) { + start = ktime_get_raw(); + + err = regmap_bulk_write(idtfc3->regmap, TOD_SYNC_LOAD_VAL_CTRL, + &buf, sizeof(buf)); + if (err) + return err; + + stop = ktime_get_raw(); + + diff = ktime_sub(stop, start); + + current_ns = ktime_to_ns(diff); + + if (i == 0) { + lowest_ns = current_ns; + } else { + if (current_ns < lowest_ns) + lowest_ns = current_ns; + } + } + + idtfc3->tod_write_overhead = lowest_ns; + + return err; +} + +static int idtfc3_enable_ptp(struct idtfc3 *idtfc3) +{ + int err; + + idtfc3->caps = idtfc3_caps; + snprintf(idtfc3->caps.name, sizeof(idtfc3->caps.name), "IDT FC3W"); + idtfc3->ptp_clock = ptp_clock_register(&idtfc3->caps, NULL); + + if (IS_ERR(idtfc3->ptp_clock)) { + err = PTR_ERR(idtfc3->ptp_clock); + idtfc3->ptp_clock = NULL; + return err; + } + + err = idtfc3_set_overhead(idtfc3); + if (err) + return err; + + err = idtfc3_init_timecounter(idtfc3); + if (err) + return err; + + dev_info(idtfc3->dev, "TIME_SYNC_CHANNEL registered as ptp%d", + idtfc3->ptp_clock->index); + + return 0; +} + +static int idtfc3_load_firmware(struct idtfc3 *idtfc3) +{ + char fname[128] = FW_FILENAME; + const struct firmware *fw; + struct idtfc3_fwrc *rec; + u16 addr; + u8 val; + int err; + s32 len; + + idtfc3_default_hw_param(&idtfc3->hw_param); + + if (firmware) /* module parameter */ + snprintf(fname, sizeof(fname), "%s", firmware); + + dev_info(idtfc3->dev, "requesting firmware '%s'\n", fname); + + err = request_firmware(&fw, fname, idtfc3->dev); + + if (err) { + dev_err(idtfc3->dev, + "requesting firmware failed with err %d!\n", err); + return err; + } + + dev_dbg(idtfc3->dev, "firmware size %zu bytes\n", fw->size); + + rec = (struct idtfc3_fwrc *)fw->data; + + for (len = fw->size; len > 0; len -= sizeof(*rec)) { + if (rec->reserved) { + dev_err(idtfc3->dev, + "bad firmware, reserved field non-zero\n"); + err = -EINVAL; + } else { + val = rec->value; + addr = rec->hiaddr << 8 | rec->loaddr; + + rec++; + + err = idtfc3_set_hw_param(&idtfc3->hw_param, addr, val); + } + + if (err != -EINVAL) { + err = 0; + + /* Max register */ + if (addr >= 0xE88) + continue; + + err = regmap_bulk_write(idtfc3->regmap, addr, + &val, sizeof(val)); + } + + if (err) + goto out; + } + + err = idtfc3_configure_hw(idtfc3); +out: + release_firmware(fw); + return err; +} + +static int idtfc3_read_device_id(struct idtfc3 *idtfc3, u16 *device_id) +{ + int err; + u8 buf[2] = {0}; + + err = regmap_bulk_read(idtfc3->regmap, DEVICE_ID, + &buf, sizeof(buf)); + if (err) { + dev_err(idtfc3->dev, "%s failed with %d", __func__, err); + return err; + } + + *device_id = get_unaligned_le16(buf); + + return 0; +} + +static int idtfc3_check_device_compatibility(struct idtfc3 *idtfc3) +{ + int err; + u16 device_id; + + err = idtfc3_read_device_id(idtfc3, &device_id); + if (err) + return err; + + if ((device_id & DEVICE_ID_MASK) == 0) { + dev_err(idtfc3->dev, "invalid device"); + return -EINVAL; + } + + return 0; +} + +static int idtfc3_probe(struct platform_device *pdev) +{ + struct rsmu_ddata *ddata = dev_get_drvdata(pdev->dev.parent); + struct idtfc3 *idtfc3; + int err; + + idtfc3 = devm_kzalloc(&pdev->dev, sizeof(struct idtfc3), GFP_KERNEL); + + if (!idtfc3) + return -ENOMEM; + + idtfc3->dev = &pdev->dev; + idtfc3->mfd = pdev->dev.parent; + idtfc3->lock = &ddata->lock; + idtfc3->regmap = ddata->regmap; + + mutex_lock(idtfc3->lock); + + err = idtfc3_check_device_compatibility(idtfc3); + if (err) { + mutex_unlock(idtfc3->lock); + return err; + } + + err = idtfc3_load_firmware(idtfc3); + if (err) { + if (err == -ENOENT) { + mutex_unlock(idtfc3->lock); + return -EPROBE_DEFER; + } + dev_warn(idtfc3->dev, "loading firmware failed with %d", err); + } + + err = idtfc3_enable_ptp(idtfc3); + if (err) { + dev_err(idtfc3->dev, "idtfc3_enable_ptp failed with %d", err); + mutex_unlock(idtfc3->lock); + return err; + } + + mutex_unlock(idtfc3->lock); + + if (err) { + ptp_clock_unregister(idtfc3->ptp_clock); + return err; + } + + platform_set_drvdata(pdev, idtfc3); + + return 0; +} + +static int idtfc3_remove(struct platform_device *pdev) +{ + struct idtfc3 *idtfc3 = platform_get_drvdata(pdev); + + ptp_clock_unregister(idtfc3->ptp_clock); + + return 0; +} + +static struct platform_driver idtfc3_driver = { + .driver = { + .name = "rc38xxx-phc", + }, + .probe = idtfc3_probe, + .remove = idtfc3_remove, +}; + +module_platform_driver(idtfc3_driver); diff --git a/drivers/ptp/ptp_fc3.h b/drivers/ptp/ptp_fc3.h new file mode 100644 index 000000000000..897101579207 --- /dev/null +++ b/drivers/ptp/ptp_fc3.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * PTP hardware clock driver for the FemtoClock3 family of timing and + * synchronization devices. + * + * Copyright (C) 2023 Integrated Device Technology, Inc., a Renesas Company. + */ +#ifndef PTP_IDTFC3_H +#define PTP_IDTFC3_H + +#include <linux/ktime.h> +#include <linux/ptp_clock.h> +#include <linux/regmap.h> + +#define FW_FILENAME "idtfc3.bin" + +#define MAX_FFO_PPB (244000) +#define TDC_GET_PERIOD (10) + +struct idtfc3 { + struct ptp_clock_info caps; + struct ptp_clock *ptp_clock; + struct device *dev; + /* Mutex to protect operations from being interrupted */ + struct mutex *lock; + struct device *mfd; + struct regmap *regmap; + struct idtfc3_hw_param hw_param; + u32 sub_sync_count; + u32 ns_per_sync; + int tdc_offset_sign; + u64 tdc_apll_freq; + u32 time_ref_freq; + u16 fod_n; + u8 lpf_mode; + /* Time counter */ + u32 last_counter; + s64 ns; + u32 ns_per_counter; + u32 tc_update_period; + u32 tc_write_timeout; + s64 tod_write_overhead; +}; + +#endif /* PTP_IDTFC3_H */ diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index 5f858e426bbd..9507681e0d12 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -4209,10 +4209,11 @@ ptp_ocp_detach(struct ptp_ocp *bp) device_unregister(&bp->dev); } -static int ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, - void *priv, - enum dpll_lock_status *status, - struct netlink_ext_ack *extack) +static int +ptp_ocp_dpll_lock_status_get(const struct dpll_device *dpll, void *priv, + enum dpll_lock_status *status, + enum dpll_lock_status_error *status_error, + struct netlink_ext_ack *extack) { struct ptp_ocp *bp = priv; diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c index f7a499a1bd39..a15460aaa03b 100644 --- a/drivers/ptp/ptp_sysfs.c +++ b/drivers/ptp/ptp_sysfs.c @@ -24,8 +24,7 @@ static ssize_t max_phase_adjustment_show(struct device *dev, { struct ptp_clock *ptp = dev_get_drvdata(dev); - return snprintf(page, PAGE_SIZE - 1, "%d\n", - ptp->info->getmaxphase(ptp->info)); + return sysfs_emit(page, "%d\n", ptp->info->getmaxphase(ptp->info)); } static DEVICE_ATTR_RO(max_phase_adjustment); @@ -34,7 +33,7 @@ static ssize_t var##_show(struct device *dev, \ struct device_attribute *attr, char *page) \ { \ struct ptp_clock *ptp = dev_get_drvdata(dev); \ - return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->var); \ + return sysfs_emit(page, "%d\n", ptp->info->var); \ } \ static DEVICE_ATTR(name, 0444, var##_show, NULL); @@ -102,8 +101,8 @@ static ssize_t extts_fifo_show(struct device *dev, if (!qcnt) goto out; - cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n", - event.index, event.t.sec, event.t.nsec); + cnt = sysfs_emit(page, "%u %lld %u\n", + event.index, event.t.sec, event.t.nsec); out: return cnt; } @@ -194,7 +193,7 @@ static ssize_t n_vclocks_show(struct device *dev, if (mutex_lock_interruptible(&ptp->n_vclocks_mux)) return -ERESTARTSYS; - size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->n_vclocks); + size = sysfs_emit(page, "%u\n", ptp->n_vclocks); mutex_unlock(&ptp->n_vclocks_mux); @@ -270,7 +269,7 @@ static ssize_t max_vclocks_show(struct device *dev, struct ptp_clock *ptp = dev_get_drvdata(dev); ssize_t size; - size = snprintf(page, PAGE_SIZE - 1, "%u\n", ptp->max_vclocks); + size = sysfs_emit(page, "%u\n", ptp->max_vclocks); return size; } |