Skip to content

Commit d156576

Browse files
ffainellidavem330
authored andcommitted
net: systemport: Establish lower/upper queue mapping
Establish a queue mapping between the DSA slave network device queues created that correspond to switch port queues, and the transmit queue that SYSTEMPORT manages. We need to configure the SYSTEMPORT transmit queue with the switch port number and switch port queue number in order for the switch and SYSTEMPORT hardware to utilize the out of band congestion notification. This hardware mechanism works by looking at the switch port egress queue and determines whether there is enough buffers for this queue, with that class of service for a successful transmission and if not, backpressures the SYSTEMPORT queue that is being used. For this to work, we implement a notifier which looks at the DSA_PORT_REGISTER event. When DSA network devices are registered, the framework calls the DSA notifiers when that happens, extracts the number of queues for these devices and their associated port number, remembers that in the driver private structure and linearly maps those queues to TX rings/queues that we manage. This scheme works because DSA slave network deviecs always transmit through SYSTEMPORT so when DSA slave network devices are destroyed/brought down, the corresponding SYSTEMPORT queues are no longer used. Also, by design of the DSA framework, the master network device (SYSTEMPORT) is registered first. For faster lookups we use an array of up to DSA_MAX_PORTS * number of queues per port, and then map pointers to bcm_sysport_tx_ring such that our ndo_select_queue() implementation can just index into that array to locate the corresponding ring index. Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0a5f14c commit d156576

File tree

2 files changed

+121
-5
lines changed

2 files changed

+121
-5
lines changed

drivers/net/ethernet/broadcom/bcmsysport.c

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,7 +1416,14 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
14161416
tdma_writel(priv, 0, TDMA_DESC_RING_COUNT(index));
14171417
tdma_writel(priv, 1, TDMA_DESC_RING_INTR_CONTROL(index));
14181418
tdma_writel(priv, 0, TDMA_DESC_RING_PROD_CONS_INDEX(index));
1419-
tdma_writel(priv, RING_IGNORE_STATUS, TDMA_DESC_RING_MAPPING(index));
1419+
1420+
/* Configure QID and port mapping */
1421+
reg = tdma_readl(priv, TDMA_DESC_RING_MAPPING(index));
1422+
reg &= ~(RING_QID_MASK | RING_PORT_ID_MASK << RING_PORT_ID_SHIFT);
1423+
reg |= ring->switch_queue & RING_QID_MASK;
1424+
reg |= ring->switch_port << RING_PORT_ID_SHIFT;
1425+
reg |= RING_IGNORE_STATUS;
1426+
tdma_writel(priv, reg, TDMA_DESC_RING_MAPPING(index));
14201427
tdma_writel(priv, 0, TDMA_DESC_RING_PCP_DEI_VID(index));
14211428

14221429
/* Do not use tdma_control_bit() here because TSB_SWAP1 collides
@@ -1447,8 +1454,9 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
14471454
napi_enable(&ring->napi);
14481455

14491456
netif_dbg(priv, hw, priv->netdev,
1450-
"TDMA cfg, size=%d, desc_cpu=%p\n",
1451-
ring->size, ring->desc_cpu);
1457+
"TDMA cfg, size=%d, desc_cpu=%p switch q=%d,port=%d\n",
1458+
ring->size, ring->desc_cpu, ring->switch_queue,
1459+
ring->switch_port);
14521460

14531461
return 0;
14541462
}
@@ -2011,6 +2019,92 @@ static const struct ethtool_ops bcm_sysport_ethtool_ops = {
20112019
.set_link_ksettings = phy_ethtool_set_link_ksettings,
20122020
};
20132021

2022+
static u16 bcm_sysport_select_queue(struct net_device *dev, struct sk_buff *skb,
2023+
void *accel_priv,
2024+
select_queue_fallback_t fallback)
2025+
{
2026+
struct bcm_sysport_priv *priv = netdev_priv(dev);
2027+
u16 queue = skb_get_queue_mapping(skb);
2028+
struct bcm_sysport_tx_ring *tx_ring;
2029+
unsigned int q, port;
2030+
2031+
if (!netdev_uses_dsa(dev))
2032+
return fallback(dev, skb);
2033+
2034+
/* DSA tagging layer will have configured the correct queue */
2035+
q = BRCM_TAG_GET_QUEUE(queue);
2036+
port = BRCM_TAG_GET_PORT(queue);
2037+
tx_ring = priv->ring_map[q + port * priv->per_port_num_tx_queues];
2038+
2039+
return tx_ring->index;
2040+
}
2041+
2042+
static int bcm_sysport_map_queues(struct net_device *dev,
2043+
struct dsa_notifier_register_info *info)
2044+
{
2045+
struct bcm_sysport_priv *priv = netdev_priv(dev);
2046+
struct bcm_sysport_tx_ring *ring;
2047+
struct net_device *slave_dev;
2048+
unsigned int num_tx_queues;
2049+
unsigned int q, start, port;
2050+
2051+
/* We can't be setting up queue inspection for non directly attached
2052+
* switches
2053+
*/
2054+
if (info->switch_number)
2055+
return 0;
2056+
2057+
port = info->port_number;
2058+
slave_dev = info->info.dev;
2059+
2060+
/* On SYSTEMPORT Lite we have twice as less queues, so we cannot do a
2061+
* 1:1 mapping, we can only do a 2:1 mapping. By reducing the number of
2062+
* per-port (slave_dev) network devices queue, we achieve just that.
2063+
* This need to happen now before any slave network device is used such
2064+
* it accurately reflects the number of real TX queues.
2065+
*/
2066+
if (priv->is_lite)
2067+
netif_set_real_num_tx_queues(slave_dev,
2068+
slave_dev->num_tx_queues / 2);
2069+
num_tx_queues = slave_dev->real_num_tx_queues;
2070+
2071+
if (priv->per_port_num_tx_queues &&
2072+
priv->per_port_num_tx_queues != num_tx_queues)
2073+
netdev_warn(slave_dev, "asymetric number of per-port queues\n");
2074+
2075+
priv->per_port_num_tx_queues = num_tx_queues;
2076+
2077+
start = find_first_zero_bit(&priv->queue_bitmap, dev->num_tx_queues);
2078+
for (q = 0; q < num_tx_queues; q++) {
2079+
ring = &priv->tx_rings[q + start];
2080+
2081+
/* Just remember the mapping actual programming done
2082+
* during bcm_sysport_init_tx_ring
2083+
*/
2084+
ring->switch_queue = q;
2085+
ring->switch_port = port;
2086+
priv->ring_map[q + port * num_tx_queues] = ring;
2087+
2088+
/* Set all queues as being used now */
2089+
set_bit(q + start, &priv->queue_bitmap);
2090+
}
2091+
2092+
return 0;
2093+
}
2094+
2095+
static int bcm_sysport_dsa_notifier(struct notifier_block *unused,
2096+
unsigned long event, void *ptr)
2097+
{
2098+
struct dsa_notifier_register_info *info;
2099+
2100+
if (event != DSA_PORT_REGISTER)
2101+
return NOTIFY_DONE;
2102+
2103+
info = ptr;
2104+
2105+
return notifier_from_errno(bcm_sysport_map_queues(info->master, info));
2106+
}
2107+
20142108
static const struct net_device_ops bcm_sysport_netdev_ops = {
20152109
.ndo_start_xmit = bcm_sysport_xmit,
20162110
.ndo_tx_timeout = bcm_sysport_tx_timeout,
@@ -2023,6 +2117,7 @@ static const struct net_device_ops bcm_sysport_netdev_ops = {
20232117
.ndo_poll_controller = bcm_sysport_poll_controller,
20242118
#endif
20252119
.ndo_get_stats64 = bcm_sysport_get_stats64,
2120+
.ndo_select_queue = bcm_sysport_select_queue,
20262121
};
20272122

20282123
#define REV_FMT "v%2x.%02x"
@@ -2172,10 +2267,18 @@ static int bcm_sysport_probe(struct platform_device *pdev)
21722267

21732268
u64_stats_init(&priv->syncp);
21742269

2270+
priv->dsa_notifier.notifier_call = bcm_sysport_dsa_notifier;
2271+
2272+
ret = register_dsa_notifier(&priv->dsa_notifier);
2273+
if (ret) {
2274+
dev_err(&pdev->dev, "failed to register DSA notifier\n");
2275+
goto err_deregister_fixed_link;
2276+
}
2277+
21752278
ret = register_netdev(dev);
21762279
if (ret) {
21772280
dev_err(&pdev->dev, "failed to register net_device\n");
2178-
goto err_deregister_fixed_link;
2281+
goto err_deregister_notifier;
21792282
}
21802283

21812284
priv->rev = topctrl_readl(priv, REV_CNTL) & REV_MASK;
@@ -2188,6 +2291,8 @@ static int bcm_sysport_probe(struct platform_device *pdev)
21882291

21892292
return 0;
21902293

2294+
err_deregister_notifier:
2295+
unregister_dsa_notifier(&priv->dsa_notifier);
21912296
err_deregister_fixed_link:
21922297
if (of_phy_is_fixed_link(dn))
21932298
of_phy_deregister_fixed_link(dn);
@@ -2199,11 +2304,13 @@ static int bcm_sysport_probe(struct platform_device *pdev)
21992304
static int bcm_sysport_remove(struct platform_device *pdev)
22002305
{
22012306
struct net_device *dev = dev_get_drvdata(&pdev->dev);
2307+
struct bcm_sysport_priv *priv = netdev_priv(dev);
22022308
struct device_node *dn = pdev->dev.of_node;
22032309

22042310
/* Not much to do, ndo_close has been called
22052311
* and we use managed allocations
22062312
*/
2313+
unregister_dsa_notifier(&priv->dsa_notifier);
22072314
unregister_netdev(dev);
22082315
if (of_phy_is_fixed_link(dn))
22092316
of_phy_deregister_fixed_link(dn);

drivers/net/ethernet/broadcom/bcmsysport.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ struct bcm_rsb {
404404
#define RING_CONS_INDEX_MASK 0xffff
405405

406406
#define RING_MAPPING 0x14
407-
#define RING_QID_MASK 0x3
407+
#define RING_QID_MASK 0x7
408408
#define RING_PORT_ID_SHIFT 3
409409
#define RING_PORT_ID_MASK 0x7
410410
#define RING_IGNORE_STATUS (1 << 6)
@@ -712,6 +712,8 @@ struct bcm_sysport_tx_ring {
712712
struct bcm_sysport_priv *priv; /* private context backpointer */
713713
unsigned long packets; /* packets statistics */
714714
unsigned long bytes; /* bytes statistics */
715+
unsigned int switch_queue; /* switch port queue number */
716+
unsigned int switch_port; /* switch port queue number */
715717
};
716718

717719
/* Driver private structure */
@@ -765,5 +767,12 @@ struct bcm_sysport_priv {
765767

766768
/* For atomic update generic 64bit value on 32bit Machine */
767769
struct u64_stats_sync syncp;
770+
771+
/* map information between switch port queues and local queues */
772+
struct notifier_block dsa_notifier;
773+
unsigned int per_port_num_tx_queues;
774+
unsigned long queue_bitmap;
775+
struct bcm_sysport_tx_ring *ring_map[DSA_MAX_PORTS * 8];
776+
768777
};
769778
#endif /* __BCM_SYSPORT_H */

0 commit comments

Comments
 (0)