|
46 | 46 | #include "cpts.h"
|
47 | 47 | #include "davinci_cpdma.h"
|
48 | 48 |
|
| 49 | +#include <net/pkt_sched.h> |
| 50 | + |
49 | 51 | #define CPSW_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \
|
50 | 52 | NETIF_MSG_DRV | NETIF_MSG_LINK | \
|
51 | 53 | NETIF_MSG_IFUP | NETIF_MSG_INTR | \
|
@@ -154,8 +156,12 @@ do { \
|
154 | 156 | #define IRQ_NUM 2
|
155 | 157 | #define CPSW_MAX_QUEUES 8
|
156 | 158 | #define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256
|
| 159 | +#define CPSW_FIFO_QUEUE_TYPE_SHIFT 16 |
| 160 | +#define CPSW_FIFO_SHAPE_EN_SHIFT 16 |
| 161 | +#define CPSW_FIFO_RATE_EN_SHIFT 20 |
157 | 162 | #define CPSW_TC_NUM 4
|
158 | 163 | #define CPSW_FIFO_SHAPERS_NUM (CPSW_TC_NUM - 1)
|
| 164 | +#define CPSW_PCT_MASK 0x7f |
159 | 165 |
|
160 | 166 | #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT 29
|
161 | 167 | #define CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK GENMASK(2, 0)
|
@@ -458,6 +464,8 @@ struct cpsw_priv {
|
458 | 464 | bool rx_pause;
|
459 | 465 | bool tx_pause;
|
460 | 466 | bool mqprio_hw;
|
| 467 | + int fifo_bw[CPSW_TC_NUM]; |
| 468 | + int shp_cfg_speed; |
461 | 469 | u32 emac_port;
|
462 | 470 | struct cpsw_common *cpsw;
|
463 | 471 | };
|
@@ -1082,6 +1090,38 @@ static void cpsw_set_slave_mac(struct cpsw_slave *slave,
|
1082 | 1090 | slave_write(slave, mac_lo(priv->mac_addr), SA_LO);
|
1083 | 1091 | }
|
1084 | 1092 |
|
| 1093 | +static bool cpsw_shp_is_off(struct cpsw_priv *priv) |
| 1094 | +{ |
| 1095 | + struct cpsw_common *cpsw = priv->cpsw; |
| 1096 | + struct cpsw_slave *slave; |
| 1097 | + u32 shift, mask, val; |
| 1098 | + |
| 1099 | + val = readl_relaxed(&cpsw->regs->ptype); |
| 1100 | + |
| 1101 | + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; |
| 1102 | + shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; |
| 1103 | + mask = 7 << shift; |
| 1104 | + val = val & mask; |
| 1105 | + |
| 1106 | + return !val; |
| 1107 | +} |
| 1108 | + |
| 1109 | +static void cpsw_fifo_shp_on(struct cpsw_priv *priv, int fifo, int on) |
| 1110 | +{ |
| 1111 | + struct cpsw_common *cpsw = priv->cpsw; |
| 1112 | + struct cpsw_slave *slave; |
| 1113 | + u32 shift, mask, val; |
| 1114 | + |
| 1115 | + val = readl_relaxed(&cpsw->regs->ptype); |
| 1116 | + |
| 1117 | + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; |
| 1118 | + shift = CPSW_FIFO_SHAPE_EN_SHIFT + 3 * slave->slave_num; |
| 1119 | + mask = (1 << --fifo) << shift; |
| 1120 | + val = on ? val | mask : val & ~mask; |
| 1121 | + |
| 1122 | + writel_relaxed(val, &cpsw->regs->ptype); |
| 1123 | +} |
| 1124 | + |
1085 | 1125 | static void _cpsw_adjust_link(struct cpsw_slave *slave,
|
1086 | 1126 | struct cpsw_priv *priv, bool *link)
|
1087 | 1127 | {
|
@@ -1121,6 +1161,12 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave,
|
1121 | 1161 | mac_control |= BIT(4);
|
1122 | 1162 |
|
1123 | 1163 | *link = true;
|
| 1164 | + |
| 1165 | + if (priv->shp_cfg_speed && |
| 1166 | + priv->shp_cfg_speed != slave->phy->speed && |
| 1167 | + !cpsw_shp_is_off(priv)) |
| 1168 | + dev_warn(priv->dev, |
| 1169 | + "Speed was changed, CBS shaper speeds are changed!"); |
1124 | 1170 | } else {
|
1125 | 1171 | mac_control = 0;
|
1126 | 1172 | /* disable forwarding */
|
@@ -1590,6 +1636,178 @@ static int cpsw_tc_to_fifo(int tc, int num_tc)
|
1590 | 1636 | return CPSW_FIFO_SHAPERS_NUM - tc;
|
1591 | 1637 | }
|
1592 | 1638 |
|
| 1639 | +static int cpsw_set_fifo_bw(struct cpsw_priv *priv, int fifo, int bw) |
| 1640 | +{ |
| 1641 | + struct cpsw_common *cpsw = priv->cpsw; |
| 1642 | + u32 val = 0, send_pct, shift; |
| 1643 | + struct cpsw_slave *slave; |
| 1644 | + int pct = 0, i; |
| 1645 | + |
| 1646 | + if (bw > priv->shp_cfg_speed * 1000) |
| 1647 | + goto err; |
| 1648 | + |
| 1649 | + /* shaping has to stay enabled for highest fifos linearly |
| 1650 | + * and fifo bw no more then interface can allow |
| 1651 | + */ |
| 1652 | + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; |
| 1653 | + send_pct = slave_read(slave, SEND_PERCENT); |
| 1654 | + for (i = CPSW_FIFO_SHAPERS_NUM; i > 0; i--) { |
| 1655 | + if (!bw) { |
| 1656 | + if (i >= fifo || !priv->fifo_bw[i]) |
| 1657 | + continue; |
| 1658 | + |
| 1659 | + dev_warn(priv->dev, "Prev FIFO%d is shaped", i); |
| 1660 | + continue; |
| 1661 | + } |
| 1662 | + |
| 1663 | + if (!priv->fifo_bw[i] && i > fifo) { |
| 1664 | + dev_err(priv->dev, "Upper FIFO%d is not shaped", i); |
| 1665 | + return -EINVAL; |
| 1666 | + } |
| 1667 | + |
| 1668 | + shift = (i - 1) * 8; |
| 1669 | + if (i == fifo) { |
| 1670 | + send_pct &= ~(CPSW_PCT_MASK << shift); |
| 1671 | + val = DIV_ROUND_UP(bw, priv->shp_cfg_speed * 10); |
| 1672 | + if (!val) |
| 1673 | + val = 1; |
| 1674 | + |
| 1675 | + send_pct |= val << shift; |
| 1676 | + pct += val; |
| 1677 | + continue; |
| 1678 | + } |
| 1679 | + |
| 1680 | + if (priv->fifo_bw[i]) |
| 1681 | + pct += (send_pct >> shift) & CPSW_PCT_MASK; |
| 1682 | + } |
| 1683 | + |
| 1684 | + if (pct >= 100) |
| 1685 | + goto err; |
| 1686 | + |
| 1687 | + slave_write(slave, send_pct, SEND_PERCENT); |
| 1688 | + priv->fifo_bw[fifo] = bw; |
| 1689 | + |
| 1690 | + dev_warn(priv->dev, "set FIFO%d bw = %d\n", fifo, |
| 1691 | + DIV_ROUND_CLOSEST(val * priv->shp_cfg_speed, 100)); |
| 1692 | + |
| 1693 | + return 0; |
| 1694 | +err: |
| 1695 | + dev_err(priv->dev, "Bandwidth doesn't fit in tc configuration"); |
| 1696 | + return -EINVAL; |
| 1697 | +} |
| 1698 | + |
| 1699 | +static int cpsw_set_fifo_rlimit(struct cpsw_priv *priv, int fifo, int bw) |
| 1700 | +{ |
| 1701 | + struct cpsw_common *cpsw = priv->cpsw; |
| 1702 | + struct cpsw_slave *slave; |
| 1703 | + u32 tx_in_ctl_rg, val; |
| 1704 | + int ret; |
| 1705 | + |
| 1706 | + ret = cpsw_set_fifo_bw(priv, fifo, bw); |
| 1707 | + if (ret) |
| 1708 | + return ret; |
| 1709 | + |
| 1710 | + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; |
| 1711 | + tx_in_ctl_rg = cpsw->version == CPSW_VERSION_1 ? |
| 1712 | + CPSW1_TX_IN_CTL : CPSW2_TX_IN_CTL; |
| 1713 | + |
| 1714 | + if (!bw) |
| 1715 | + cpsw_fifo_shp_on(priv, fifo, bw); |
| 1716 | + |
| 1717 | + val = slave_read(slave, tx_in_ctl_rg); |
| 1718 | + if (cpsw_shp_is_off(priv)) { |
| 1719 | + /* disable FIFOs rate limited queues */ |
| 1720 | + val &= ~(0xf << CPSW_FIFO_RATE_EN_SHIFT); |
| 1721 | + |
| 1722 | + /* set type of FIFO queues to normal priority mode */ |
| 1723 | + val &= ~(3 << CPSW_FIFO_QUEUE_TYPE_SHIFT); |
| 1724 | + |
| 1725 | + /* set type of FIFO queues to be rate limited */ |
| 1726 | + if (bw) |
| 1727 | + val |= 2 << CPSW_FIFO_QUEUE_TYPE_SHIFT; |
| 1728 | + else |
| 1729 | + priv->shp_cfg_speed = 0; |
| 1730 | + } |
| 1731 | + |
| 1732 | + /* toggle a FIFO rate limited queue */ |
| 1733 | + if (bw) |
| 1734 | + val |= BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); |
| 1735 | + else |
| 1736 | + val &= ~BIT(fifo + CPSW_FIFO_RATE_EN_SHIFT); |
| 1737 | + slave_write(slave, val, tx_in_ctl_rg); |
| 1738 | + |
| 1739 | + /* FIFO transmit shape enable */ |
| 1740 | + cpsw_fifo_shp_on(priv, fifo, bw); |
| 1741 | + return 0; |
| 1742 | +} |
| 1743 | + |
| 1744 | +/* Defaults: |
| 1745 | + * class A - prio 3 |
| 1746 | + * class B - prio 2 |
| 1747 | + * shaping for class A should be set first |
| 1748 | + */ |
| 1749 | +static int cpsw_set_cbs(struct net_device *ndev, |
| 1750 | + struct tc_cbs_qopt_offload *qopt) |
| 1751 | +{ |
| 1752 | + struct cpsw_priv *priv = netdev_priv(ndev); |
| 1753 | + struct cpsw_common *cpsw = priv->cpsw; |
| 1754 | + struct cpsw_slave *slave; |
| 1755 | + int prev_speed = 0; |
| 1756 | + int tc, ret, fifo; |
| 1757 | + u32 bw = 0; |
| 1758 | + |
| 1759 | + tc = netdev_txq_to_tc(priv->ndev, qopt->queue); |
| 1760 | + |
| 1761 | + /* enable channels in backward order, as highest FIFOs must be rate |
| 1762 | + * limited first and for compliance with CPDMA rate limited channels |
| 1763 | + * that also used in bacward order. FIFO0 cannot be rate limited. |
| 1764 | + */ |
| 1765 | + fifo = cpsw_tc_to_fifo(tc, ndev->num_tc); |
| 1766 | + if (!fifo) { |
| 1767 | + dev_err(priv->dev, "Last tc%d can't be rate limited", tc); |
| 1768 | + return -EINVAL; |
| 1769 | + } |
| 1770 | + |
| 1771 | + /* do nothing, it's disabled anyway */ |
| 1772 | + if (!qopt->enable && !priv->fifo_bw[fifo]) |
| 1773 | + return 0; |
| 1774 | + |
| 1775 | + /* shapers can be set if link speed is known */ |
| 1776 | + slave = &cpsw->slaves[cpsw_slave_index(cpsw, priv)]; |
| 1777 | + if (slave->phy && slave->phy->link) { |
| 1778 | + if (priv->shp_cfg_speed && |
| 1779 | + priv->shp_cfg_speed != slave->phy->speed) |
| 1780 | + prev_speed = priv->shp_cfg_speed; |
| 1781 | + |
| 1782 | + priv->shp_cfg_speed = slave->phy->speed; |
| 1783 | + } |
| 1784 | + |
| 1785 | + if (!priv->shp_cfg_speed) { |
| 1786 | + dev_err(priv->dev, "Link speed is not known"); |
| 1787 | + return -1; |
| 1788 | + } |
| 1789 | + |
| 1790 | + ret = pm_runtime_get_sync(cpsw->dev); |
| 1791 | + if (ret < 0) { |
| 1792 | + pm_runtime_put_noidle(cpsw->dev); |
| 1793 | + return ret; |
| 1794 | + } |
| 1795 | + |
| 1796 | + bw = qopt->enable ? qopt->idleslope : 0; |
| 1797 | + ret = cpsw_set_fifo_rlimit(priv, fifo, bw); |
| 1798 | + if (ret) { |
| 1799 | + priv->shp_cfg_speed = prev_speed; |
| 1800 | + prev_speed = 0; |
| 1801 | + } |
| 1802 | + |
| 1803 | + if (bw && prev_speed) |
| 1804 | + dev_warn(priv->dev, |
| 1805 | + "Speed was changed, CBS shaper speeds are changed!"); |
| 1806 | + |
| 1807 | + pm_runtime_put_sync(cpsw->dev); |
| 1808 | + return ret; |
| 1809 | +} |
| 1810 | + |
1593 | 1811 | static int cpsw_ndo_open(struct net_device *ndev)
|
1594 | 1812 | {
|
1595 | 1813 | struct cpsw_priv *priv = netdev_priv(ndev);
|
@@ -2264,6 +2482,9 @@ static int cpsw_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
|
2264 | 2482 | void *type_data)
|
2265 | 2483 | {
|
2266 | 2484 | switch (type) {
|
| 2485 | + case TC_SETUP_QDISC_CBS: |
| 2486 | + return cpsw_set_cbs(ndev, type_data); |
| 2487 | + |
2267 | 2488 | case TC_SETUP_QDISC_MQPRIO:
|
2268 | 2489 | return cpsw_set_mqprio(ndev, type_data);
|
2269 | 2490 |
|
|
0 commit comments