staticint
qca8k_mii_write_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
{ int ret;
u16 lo;
lo = val & 0xffff;
ret = bus->write(bus, phy_id, regnum, lo); if (ret < 0)
dev_err_ratelimited(&bus->dev, "failed to write qca8k 32bit lo register\n");
return ret;
}
staticint
qca8k_mii_write_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
{ int ret;
u16 hi;
hi = (u16)(val >> 16);
ret = bus->write(bus, phy_id, regnum, hi); if (ret < 0)
dev_err_ratelimited(&bus->dev, "failed to write qca8k 32bit hi register\n");
return ret;
}
staticint
qca8k_mii_read_lo(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
{ int ret;
ret = bus->read(bus, phy_id, regnum); if (ret < 0) goto err;
*val = ret & 0xffff; return 0;
err:
dev_err_ratelimited(&bus->dev, "failed to read qca8k 32bit lo register\n");
*val = 0;
return ret;
}
staticint
qca8k_mii_read_hi(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
{ int ret;
ret = bus->read(bus, phy_id, regnum); if (ret < 0) goto err;
*val = ret << 16; return 0;
err:
dev_err_ratelimited(&bus->dev, "failed to read qca8k 32bit hi register\n");
*val = 0;
return ret;
}
staticint
qca8k_mii_read32(struct mii_bus *bus, int phy_id, u32 regnum, u32 *val)
{
u32 hi, lo; int ret;
*val = 0;
ret = qca8k_mii_read_lo(bus, phy_id, regnum, &lo); if (ret < 0) goto err;
ret = qca8k_mii_read_hi(bus, phy_id, regnum + 1, &hi); if (ret < 0) goto err;
*val = lo | hi;
err: return ret;
}
staticvoid
qca8k_mii_write32(struct mii_bus *bus, int phy_id, u32 regnum, u32 val)
{ if (qca8k_mii_write_lo(bus, phy_id, regnum, val) < 0) return;
qca8k_mii_write_hi(bus, phy_id, regnum + 1, val);
}
len = FIELD_GET(QCA_HDR_MGMT_LENGTH, command); /* Special case for len of 15 as this is the max value for len and needs to * be increased before converting it from word to dword.
*/ if (len == 15)
len++;
/* We can ignore odd value, we always round up them in the alloc function. */
len *= sizeof(u16);
/* Make sure the seq match the requested packet */ if (get_unaligned_le32(&mgmt_ethhdr->seq) == mgmt_eth_data->seq)
mgmt_eth_data->ack = true;
if (cmd == MDIO_READ) {
u32 *val = mgmt_eth_data->data;
/* Get the rest of the 12 byte of data. * The read/write function will extract the requested data.
*/ if (len > QCA_HDR_MGMT_DATA1_LEN) {
__le32 *data2 = (__le32 *)skb->data; int data_len = min_t(int, QCA_HDR_MGMT_DATA2_LEN,
len - QCA_HDR_MGMT_DATA1_LEN);
val++;
for (i = sizeof(u32); i <= data_len; i += sizeof(u32)) {
*val = get_unaligned_le32(data2);
val++;
data2++;
}
}
}
skb = dev_alloc_skb(QCA_HDR_MGMT_PKT_LEN); if (!skb) return NULL;
/* Hdr mgmt length value is in step of word size. * As an example to process 4 byte of data the correct length to set is 2. * To process 8 byte 4, 12 byte 6, 16 byte 8... * * Odd values will always return the next size on the ack packet. * (length of 3 (6 byte) will always return 8 bytes of data) * * This means that a value of 15 (0xf) actually means reading/writing 32 bytes * of data. * * To correctly calculate the length we devide the requested len by word and * round up. * On the ack function we can skip the odd check as we already handle the * case here.
*/
real_len = DIV_ROUND_UP(len, sizeof(u16));
/* We check if the result len is odd and we round up another time to * the next size. (length of 3 will be increased to 4 as switch will always * return 8 bytes)
*/ if (real_len % sizeof(u16) != 0)
real_len++;
/* Max reg value is 0xf(15) but switch will always return the next size (32 byte) */ if (real_len == 16)
real_len--;
/* Check if the mgmt_conduit if is operational */ if (!priv->mgmt_conduit) {
kfree_skb(skb);
mutex_unlock(&mgmt_eth_data->mutex); return -EINVAL;
}
skb->dev = priv->mgmt_conduit;
reinit_completion(&mgmt_eth_data->rw_done);
/* Increment seq_num and set it in the mdio pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
dev_queue_xmit(skb);
ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
QCA8K_ETHERNET_TIMEOUT);
*val = mgmt_eth_data->data[0]; if (len > QCA_HDR_MGMT_DATA1_LEN)
memcpy(val + 1, mgmt_eth_data->data + 1, len - QCA_HDR_MGMT_DATA1_LEN);
/* Check if the mgmt_conduit if is operational */ if (!priv->mgmt_conduit) {
kfree_skb(skb);
mutex_unlock(&mgmt_eth_data->mutex); return -EINVAL;
}
skb->dev = priv->mgmt_conduit;
reinit_completion(&mgmt_eth_data->rw_done);
/* Increment seq_num and set it in the mdio pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
dev_queue_xmit(skb);
ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
mutex_unlock(&mgmt_eth_data->mutex);
if (ret <= 0) return -ETIMEDOUT;
if (!ack) return -EINVAL;
return 0;
}
staticint
qca8k_regmap_update_bits_eth(struct qca8k_priv *priv, u32 reg, u32 mask, u32 write_val)
{
u32 val = 0; int ret;
ret = qca8k_read_eth(priv, reg, &val, sizeof(val)); if (ret) return ret;
if (priv->mgmt_conduit &&
!qca8k_read_eth(priv, reg, val_buf, val_len)) return 0;
/* loop count times and increment reg of 4 */ for (i = 0; i < count; i++, reg += sizeof(u32)) {
ret = qca8k_read_mii(priv, reg, val_buf + i); if (ret < 0) return ret;
}
if (priv->mgmt_conduit &&
!qca8k_write_eth(priv, reg, val, val_len)) return 0;
/* loop count times, increment reg of 4 and increment val ptr to * the next value
*/ for (i = 0; i < count; i++, reg += sizeof(u32), val++) {
ret = qca8k_write_mii(priv, reg, *val); if (ret < 0) return ret;
}
/* Increment seq_num and set it in the copy pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
dev_queue_xmit(skb);
ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
QCA8K_ETHERNET_TIMEOUT);
/* Prealloc all the needed skb before the lock */
write_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &write_val,
QCA8K_ETHERNET_PHY_PRIORITY, sizeof(write_val)); if (!write_skb) return -ENOMEM;
clear_skb = qca8k_alloc_mdio_header(MDIO_WRITE, QCA8K_MDIO_MASTER_CTRL, &clear_val,
QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); if (!clear_skb) {
ret = -ENOMEM; goto err_clear_skb;
}
read_skb = qca8k_alloc_mdio_header(MDIO_READ, QCA8K_MDIO_MASTER_CTRL, &clear_val,
QCA8K_ETHERNET_PHY_PRIORITY, sizeof(clear_val)); if (!read_skb) {
ret = -ENOMEM; goto err_read_skb;
}
/* It seems that accessing the switch's internal PHYs via management * packets still uses the MDIO bus within the switch internally, and * these accesses can conflict with external MDIO accesses to other * devices on the MDIO bus. * We therefore need to lock the MDIO bus onto which the switch is * connected.
*/
mutex_lock_nested(&priv->bus->mdio_lock, MDIO_MUTEX_NESTED);
/* Actually start the request: * 1. Send mdio master packet * 2. Busy Wait for mdio master command * 3. Get the data if we are reading * 4. Reset the mdio master (even with error)
*/
mutex_lock(&mgmt_eth_data->mutex);
/* Check if mgmt_conduit is operational */
mgmt_conduit = priv->mgmt_conduit; if (!mgmt_conduit) {
mutex_unlock(&mgmt_eth_data->mutex);
mutex_unlock(&priv->bus->mdio_lock);
ret = -EINVAL; goto err_mgmt_conduit;
}
/* Increment seq_num and set it in the write pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(write_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
dev_queue_xmit(write_skb);
ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
QCA8K_ETHERNET_TIMEOUT);
ack = mgmt_eth_data->ack;
if (ret <= 0) {
ret = -ETIMEDOUT;
kfree_skb(read_skb); gotoexit;
}
if (!ack) {
ret = -EINVAL;
kfree_skb(read_skb); gotoexit;
}
if (ret < 0 && ret1 < 0) {
ret = ret1; gotoexit;
}
if (read) {
reinit_completion(&mgmt_eth_data->rw_done);
/* Increment seq_num and set it in the read pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(read_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
dev_queue_xmit(read_skb);
ret = wait_for_completion_timeout(&mgmt_eth_data->rw_done,
QCA8K_ETHERNET_TIMEOUT);
/* Increment seq_num and set it in the clear pkt */
mgmt_eth_data->seq++;
qca8k_mdio_header_fill_seq_num(clear_skb, mgmt_eth_data->seq);
mgmt_eth_data->ack = false;
ret = qca8k_set_page(priv, page); if (ret) gotoexit;
qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, val);
ret = qca8k_mdio_busy_wait(bus, QCA8K_MDIO_MASTER_CTRL,
QCA8K_MDIO_MASTER_BUSY); if (ret) gotoexit;
ret = qca8k_mii_read_lo(bus, 0x10 | r2, r1, &val);
exit: /* even if the busy_wait timeouts try to clear the MASTER_EN */
qca8k_mii_write_hi(bus, 0x10 | r2, r1 + 1, 0);
mutex_unlock(&bus->mdio_lock);
if (ret >= 0)
ret = val & QCA8K_MDIO_MASTER_DATA_MASK;
return ret;
}
staticint
qca8k_internal_mdio_write(struct mii_bus *slave_bus, int phy, int regnum, u16 data)
{ struct qca8k_priv *priv = slave_bus->priv; int ret;
/* Use mdio Ethernet when available, fallback to legacy one on error */
ret = qca8k_phy_eth_command(priv, false, phy, regnum, data); if (!ret) return 0;
staticint
qca8k_internal_mdio_read(struct mii_bus *slave_bus, int phy, int regnum)
{ struct qca8k_priv *priv = slave_bus->priv; int ret;
/* Use mdio Ethernet when available, fallback to legacy one on error */
ret = qca8k_phy_eth_command(priv, true, phy, regnum, 0); if (ret >= 0) return ret;
ret = qca8k_mdio_read(priv, phy, regnum);
if (ret < 0) return 0xffff;
return ret;
}
staticint
qca8k_legacy_mdio_write(struct mii_bus *slave_bus, int port, int regnum, u16 data)
{
port = qca8k_port_to_phy(port) % PHY_MAX_ADDR;
if (mdio) { /* Check if the device tree declares the port:phy mapping */
bus->name = "qca8k user mii";
bus->read = qca8k_internal_mdio_read;
bus->write = qca8k_internal_mdio_write;
} else { /* If a mapping can't be found, the legacy mapping is used, * using qca8k_port_to_phy()
*/
ds->user_mii_bus = bus;
bus->phy_mask = ~ds->phys_mii_mask;
bus->name = "qca8k-legacy user mii";
bus->read = qca8k_legacy_mdio_read;
bus->write = qca8k_legacy_mdio_write;
}
of_node_put(ports); if (!external_mdio_mask && !internal_mdio_mask) {
dev_err(priv->dev, "no PHYs are defined.\n"); return -EINVAL;
}
/* The QCA8K_MDIO_MASTER_EN Bit, which grants access to PHYs through * the MDIO_MASTER register also _disconnects_ the external MDC * passthrough to the internal PHYs. It's not possible to use both * configurations at the same time! * * Because this came up during the review process: * If the external mdio-bus driver is capable magically disabling * the QCA8K_MDIO_MASTER_EN and mutex/spin-locking out the qca8k's * accessors for the time being, it would be possible to pull this * off.
*/ if (!!external_mdio_mask && !!internal_mdio_mask) {
dev_err(priv->dev, "either internal or external mdio bus configuration is supported.\n"); return -EINVAL;
}
if (external_mdio_mask) { /* Make sure to disable the internal mdio bus in cases * a dt-overlay and driver reload changed the configuration
*/
staticint
qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
{
u32 mask = 0; int ret = 0;
/* SoC specific settings for ipq8064. * If more device require this consider adding * a dedicated binding.
*/ if (of_machine_is_compatible("qcom,ipq8064"))
mask |= QCA8K_MAC_PWR_RGMII0_1_8V;
/* SoC specific settings for ipq8065 */ if (of_machine_is_compatible("qcom,ipq8065"))
mask |= QCA8K_MAC_PWR_RGMII1_1_8V;
if (mask) {
ret = qca8k_rmw(priv, QCA8K_REG_MAC_PWR_SEL,
QCA8K_MAC_PWR_RGMII0_1_8V |
QCA8K_MAC_PWR_RGMII1_1_8V,
mask);
}
/* QCA8327 require to set to the correct mode. * His bigger brother QCA8328 have the 172 pin layout. * Should be applied by default but we set this just to make sure.
*/ if (priv->switch_id == QCA8K_ID_QCA8327) { /* Set the correct package of 148 pin for QCA8327 */ if (data->reduced_package)
val |= QCA8327_PWS_PACKAGE148_EN;
ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8327_PWS_PACKAGE148_EN,
val); if (ret) return ret;
}
if (of_property_read_bool(node, "qca,ignore-power-on-sel"))
val |= QCA8K_PWS_POWER_ON_SEL;
if (of_property_read_bool(node, "qca,led-open-drain")) { if (!(val & QCA8K_PWS_POWER_ON_SEL)) {
dev_err(priv->dev, "qca,led-open-drain require qca,ignore-power-on-sel to be set."); return -EINVAL;
}
/* We have 2 CPU port. Check them */ for (port = 0; port < QCA8K_NUM_PORTS; port++) { /* Skip every other port */ if (port != 0 && port != 6) continue;
ret = of_get_phy_mode(port_dn, &mode); if (ret) continue;
switch (mode) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_SGMII:
delay = 0;
if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay)) /* Switch regs accept value in ns, convert ps to ns */
delay = delay / 1000; elseif (mode == PHY_INTERFACE_MODE_RGMII_ID ||
mode == PHY_INTERFACE_MODE_RGMII_TXID)
delay = 1;
if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK, delay)) {
dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
delay = 3;
}
if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay)) /* Switch regs accept value in ns, convert ps to ns */
delay = delay / 1000; elseif (mode == PHY_INTERFACE_MODE_RGMII_ID ||
mode == PHY_INTERFACE_MODE_RGMII_RXID)
delay = 2;
if (!FIELD_FIT(QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK, delay)) {
dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
delay = 3;
}
if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
priv->ports_config.sgmii_tx_clk_falling_edge = true;
if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
priv->ports_config.sgmii_rx_clk_falling_edge = true;
if (of_property_read_bool(port_dn, "qca,sgmii-enable-pll")) {
priv->ports_config.sgmii_enable_pll = true;
if (priv->switch_id == QCA8K_ID_QCA8327) {
dev_err(priv->dev, "SGMII PLL should NOT be enabled for qca8327. Aborting enabling");
priv->ports_config.sgmii_enable_pll = false;
}
if (priv->switch_revision < 2)
dev_warn(priv->dev, "SGMII PLL should NOT be enabled for qca8337 with revision 2 or more.");
}
break; default: continue;
}
}
return 0;
}
staticvoid
qca8k_mac_config_setup_internal_delay(struct qca8k_priv *priv, int cpu_port_index,
u32 reg)
{
u32 delay, val = 0; int ret;
/* Delay can be declared in 3 different way. * Mode to rgmii and internal-delay standard binding defined * rgmii-id or rgmii-tx/rx phy mode set. * The parse logic set a delay different than 0 only when one * of the 3 different way is used. In all other case delay is * not enabled. With ID or TX/RXID delay is enabled and set * to the default and recommended value.
*/ if (priv->ports_config.rgmii_tx_delay[cpu_port_index]) {
delay = priv->ports_config.rgmii_tx_delay[cpu_port_index];
val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
}
if (priv->ports_config.rgmii_rx_delay[cpu_port_index]) {
delay = priv->ports_config.rgmii_rx_delay[cpu_port_index];
val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
}
/* Set RGMII delay based on the selected values */
ret = qca8k_rmw(priv, reg,
QCA8K_PORT_PAD_RGMII_TX_DELAY_MASK |
QCA8K_PORT_PAD_RGMII_RX_DELAY_MASK |
QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN,
val); if (ret)
dev_err(priv->dev, "Failed to set internal delay for CPU port%d",
cpu_port_index == QCA8K_CPU_PORT0 ? 0 : 6);
}
switch (state->interface) { case PHY_INTERFACE_MODE_RGMII: case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_TXID: case PHY_INTERFACE_MODE_RGMII_RXID:
qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
/* QCA8337 requires to set rgmii rx delay for all ports. * This is enabled through PORT5_PAD_CTRL for all ports, * rather than individual port registers.
*/ if (priv->switch_id == QCA8K_ID_QCA8337)
qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN); break; case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_1000BASEX: /* Enable SGMII on the port */
qca8k_write(priv, reg, QCA8K_PORT_PAD_SGMII_EN); break; default:
dev_err(ds->dev, "xMII mode %s not supported for port %d\n",
phy_modes(state->interface), port); return;
}
}
staticvoid qca8k_phylink_get_caps(struct dsa_switch *ds, int port, struct phylink_config *config)
{ switch (port) { case 0: /* 1st CPU port */
phy_interface_set_rgmii(config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII,
config->supported_interfaces); break;
case 1: case 2: case 3: case 4: case 5: /* Internal PHY */
__set_bit(PHY_INTERFACE_MODE_GMII,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_INTERNAL,
config->supported_interfaces); break;
case 6: /* 2nd CPU port / external PHY */
phy_interface_set_rgmii(config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII,
config->supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_1000BASEX,
config->supported_interfaces); break;
}
port = pcs_to_qca8k_pcs(pcs)->port; switch (port) { case 0:
reg = QCA8K_REG_PORT0_PAD_CTRL;
cpu_port_index = QCA8K_CPU_PORT0; break;
case 6:
reg = QCA8K_REG_PORT6_PAD_CTRL;
cpu_port_index = QCA8K_CPU_PORT6; break;
default:
WARN_ON(1); return -EINVAL;
}
/* Enable/disable SerDes auto-negotiation as necessary */
val = neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED ?
0 : QCA8K_PWS_SERDES_AEN_DIS;
ret = qca8k_rmw(priv, QCA8K_REG_PWS, QCA8K_PWS_SERDES_AEN_DIS, val); if (ret) return ret;
/* Configure the SGMII parameters */
ret = qca8k_read(priv, QCA8K_REG_SGMII_CTRL, &val); if (ret) return ret;
val |= QCA8K_SGMII_EN_SD;
if (priv->ports_config.sgmii_enable_pll)
val |= QCA8K_SGMII_EN_PLL | QCA8K_SGMII_EN_RX |
QCA8K_SGMII_EN_TX;
if (dsa_is_cpu_port(priv->ds, port)) { /* CPU port, we're talking to the CPU MAC, be a PHY */
val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
val |= QCA8K_SGMII_MODE_CTRL_PHY;
} elseif (interface == PHY_INTERFACE_MODE_SGMII) {
val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
val |= QCA8K_SGMII_MODE_CTRL_MAC;
} elseif (interface == PHY_INTERFACE_MODE_1000BASEX) {
val &= ~QCA8K_SGMII_MODE_CTRL_MASK;
val |= QCA8K_SGMII_MODE_CTRL_BASEX;
}
qca8k_write(priv, QCA8K_REG_SGMII_CTRL, val);
/* From original code is reported port instability as SGMII also * require delay set. Apply advised values here or take them from DT.
*/ if (interface == PHY_INTERFACE_MODE_SGMII)
qca8k_mac_config_setup_internal_delay(priv, cpu_port_index, reg); /* For qca8327/qca8328/qca8334/qca8338 sgmii is unique and * falling edge is set writing in the PORT0 PAD reg
*/ if (priv->switch_id == QCA8K_ID_QCA8327 ||
priv->switch_id == QCA8K_ID_QCA8337)
reg = QCA8K_REG_PORT0_PAD_CTRL;
val = 0;
/* SGMII Clock phase configuration */ if (priv->ports_config.sgmii_rx_clk_falling_edge)
val |= QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE;
if (priv->ports_config.sgmii_tx_clk_falling_edge)
val |= QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE;
if (val)
ret = qca8k_rmw(priv, reg,
QCA8K_PORT0_PAD_SGMII_RXCLK_FALLING_EDGE |
QCA8K_PORT0_PAD_SGMII_TXCLK_FALLING_EDGE,
val);
/* The switch autocast every port. Ignore other packet and * parse only the requested one.
*/
port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, ntohs(mib_ethhdr->hdr)); if (port != mib_eth_data->req_port) gotoexit;
data2 = (__le32 *)skb->data;
for (i = 0; i < priv->info->mib_count; i++) {
mib = &ar8327_mib[i];
/* First 3 mib are present in the skb head */ if (i < 3) {
mib_eth_data->data[i] = get_unaligned_le32(mib_ethhdr->data + i); continue;
}
/* Some mib are 64 bit wide */ if (mib->size == 2)
mib_eth_data->data[i] = get_unaligned_le64((__le64 *)data2); else
mib_eth_data->data[i] = get_unaligned_le32(data2);
data2 += mib->size;
}
exit: /* Complete on receiving all the mib packet */ if (refcount_dec_and_test(&mib_eth_data->port_parsed))
complete(&mib_eth_data->rw_done);
}
/* Communicate to the phy internal driver the switch revision. * Based on the switch revision different values needs to be * set to the dbg and mmd reg on the phy. * The first 2 bit are used to communicate the switch revision * to the phy driver.
*/ if (port > 0 && port < 6) return priv->switch_revision;
staticvoid qca8k_setup_hol_fixup(struct qca8k_priv *priv, int port)
{
u32 mask;
switch (port) { /* The 2 CPU port and port 5 requires some different * priority than any other ports.
*/ case 0: case 5: case 6:
mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x4) |
QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x4) |
QCA8K_PORT_HOL_CTRL0_EG_PRI4(0x6) |
QCA8K_PORT_HOL_CTRL0_EG_PRI5(0x8) |
QCA8K_PORT_HOL_CTRL0_EG_PORT(0x1e); break; default:
mask = QCA8K_PORT_HOL_CTRL0_EG_PRI0(0x3) |
QCA8K_PORT_HOL_CTRL0_EG_PRI1(0x4) |
QCA8K_PORT_HOL_CTRL0_EG_PRI2(0x6) |
QCA8K_PORT_HOL_CTRL0_EG_PRI3(0x8) |
QCA8K_PORT_HOL_CTRL0_EG_PORT(0x19);
}
regmap_write(priv->regmap, QCA8K_REG_PORT_HOL_CTRL0(port), mask);
/* Make sure MAC06 is disabled */
ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT0_PAD_CTRL,
QCA8K_PORT0_PAD_MAC06_EXCHANGE_EN); if (ret) {
dev_err(priv->dev, "failed disabling MAC06 exchange"); return ret;
}
/* Enable CPU Port */
ret = regmap_set_bits(priv->regmap, QCA8K_REG_GLOBAL_FW_CTRL0,
QCA8K_GLOBAL_FW_CTRL0_CPU_PORT_EN); if (ret) {
dev_err(priv->dev, "failed enabling CPU port"); return ret;
}
/* Enable MIB counters */
ret = qca8k_mib_init(priv); if (ret)
dev_warn(priv->dev, "mib init failed");
/* Initial setup of all ports */
dsa_switch_for_each_port(dp, ds) { /* Disable forwarding by default on all ports */
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(dp->index),
QCA8K_PORT_LOOKUP_MEMBER, 0); if (ret) return ret;
}
/* Disable MAC by default on all user ports */
dsa_switch_for_each_user_port(dp, ds)
qca8k_port_set_status(priv, dp->index, 0);
/* Enable QCA header mode on all cpu ports */
dsa_switch_for_each_cpu_port(dp, ds) {
ret = qca8k_write(priv, QCA8K_REG_PORT_HDR_CTRL(dp->index),
FIELD_PREP(QCA8K_PORT_HDR_CTRL_TX_MASK, QCA8K_PORT_HDR_CTRL_ALL) |
FIELD_PREP(QCA8K_PORT_HDR_CTRL_RX_MASK, QCA8K_PORT_HDR_CTRL_ALL)); if (ret) {
dev_err(priv->dev, "failed enabling QCA header mode on port %d", dp->index); return ret;
}
}
/* Forward all unknown frames to CPU port for Linux processing * Notice that in multi-cpu config only one port should be set * for igmp, unknown, multicast and broadcast packet
*/
ret = qca8k_write(priv, QCA8K_REG_GLOBAL_FW_CTRL1,
FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_IGMP_DP_MASK, BIT(cpu_port)) |
FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_BC_DP_MASK, BIT(cpu_port)) |
FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_MC_DP_MASK, BIT(cpu_port)) |
FIELD_PREP(QCA8K_GLOBAL_FW_CTRL1_UC_DP_MASK, BIT(cpu_port))); if (ret) return ret;
/* CPU port gets connected to all user ports of the switch */
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(cpu_port),
QCA8K_PORT_LOOKUP_MEMBER, dsa_user_ports(ds)); if (ret) return ret;
/* Setup connection between CPU port & user ports * Individual user ports get connected to CPU port only
*/
dsa_switch_for_each_user_port(dp, ds) {
u8 port = dp->index;
ret = qca8k_rmw(priv, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_MEMBER,
BIT(cpu_port)); if (ret) return ret;
ret = regmap_clear_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
QCA8K_PORT_LOOKUP_LEARN); if (ret) return ret;
/* For port based vlans to work we need to set the * default egress vid
*/
ret = qca8k_rmw(priv, QCA8K_EGRESS_VLAN(port),
QCA8K_EGREES_VLAN_PORT_MASK(port),
QCA8K_EGREES_VLAN_PORT(port, QCA8K_PORT_VID_DEF)); if (ret) return ret;
ret = qca8k_write(priv, QCA8K_REG_PORT_VLAN_CTRL0(port),
QCA8K_PORT_VLAN_CVID(QCA8K_PORT_VID_DEF) |
QCA8K_PORT_VLAN_SVID(QCA8K_PORT_VID_DEF)); if (ret) return ret;
}
/* The port 5 of the qca8337 have some problem in flood condition. The * original legacy driver had some specific buffer and priority settings * for the different port suggested by the QCA switch team. Add this * missing settings to improve switch stability under load condition. * This problem is limited to qca8337 and other qca8k switch are not affected.
*/ if (priv->switch_id == QCA8K_ID_QCA8337)
dsa_switch_for_each_available_port(dp, ds)
qca8k_setup_hol_fixup(priv, dp->index);
/* Special GLOBAL_FC_THRESH value are needed for ar8327 switch */ if (priv->switch_id == QCA8K_ID_QCA8327) {
mask = QCA8K_GLOBAL_FC_GOL_XON_THRES(288) |
QCA8K_GLOBAL_FC_GOL_XOFF_THRES(496);
qca8k_rmw(priv, QCA8K_REG_GLOBAL_FC_THRESH,
QCA8K_GLOBAL_FC_GOL_XON_THRES_MASK |
QCA8K_GLOBAL_FC_GOL_XOFF_THRES_MASK,
mask);
}
/* Setup our port MTUs to match power on defaults */
ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN); if (ret)
dev_warn(priv->dev, "failed setting MTU settings");
/* Flush the FDB table */
qca8k_fdb_flush(priv);
/* Set min a max ageing value supported */
ds->ageing_time_min = 7000;
ds->ageing_time_max = 458745000;
/* Set max number of LAGs supported */
ds->num_lag_ids = QCA8K_NUM_LAGS;
staticint
qca8k_sw_probe(struct mdio_device *mdiodev)
{ struct qca8k_priv *priv; int ret;
/* allocate the private data struct so that we can probe the switches * ID register
*/
priv = devm_kzalloc(&mdiodev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset",
GPIOD_OUT_HIGH); if (IS_ERR(priv->reset_gpio)) return PTR_ERR(priv->reset_gpio);
if (priv->reset_gpio) { /* The active low duration must be greater than 10 ms * and checkpatch.pl wants 20 ms.
*/
msleep(20);
gpiod_set_value_cansleep(priv->reset_gpio, 0);
}
/* Start by setting up the register mapping */
priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, priv,
&qca8k_regmap_config); if (IS_ERR(priv->regmap)) {
dev_err(priv->dev, "regmap initialization failed"); return PTR_ERR(priv->regmap);
}
priv->mdio_cache.page = 0xffff;
/* Check the detected switch id */
ret = qca8k_read_switch_id(priv); if (ret) return ret;
priv->ds = devm_kzalloc(&mdiodev->dev, sizeof(*priv->ds), GFP_KERNEL); if (!priv->ds) return -ENOMEM;
#ifdef CONFIG_PM_SLEEP staticvoid
qca8k_set_pm(struct qca8k_priv *priv, int enable)
{ int port;
for (port = 0; port < QCA8K_NUM_PORTS; port++) { /* Do not enable on resume if the port was * disabled before.
*/ if (!(priv->port_enabled_map & BIT(port))) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.