diff options
author | Reece R. Pollack | 2015-02-20 17:36:40 -0600 |
---|---|---|
committer | Reece R. Pollack | 2015-02-27 14:43:29 -0600 |
commit | 2f549b1ea2418bc30bbfd624b2f4fd2255fb3e82 (patch) | |
tree | 99b004adf2be12583a59ef1102d45c6669a10e8b | |
parent | 639ea778eadd4f5b0a85acac872f50085826d511 (diff) | |
download | linux-2f549b1ea2418bc30bbfd624b2f4fd2255fb3e82.tar.gz linux-2f549b1ea2418bc30bbfd624b2f4fd2255fb3e82.tar.xz linux-2f549b1ea2418bc30bbfd624b2f4fd2255fb3e82.zip |
net: keystone: Add TX queue depth resizing to NetCP QoS
This patch makes the TX queue depths (really the number of DMA
descriptors available) visible and modifiable in sysfs. This
also exposes queue name and device multi-interface mode.
This patch provides these features in the NetCP QoS module ONLY,
and does not apply to other NetCP modules (PA, SA, etc).
Signed-off-by: Reece R. Pollack <x0183204@ti.com>
-rw-r--r-- | drivers/net/ethernet/ti/keystone_net_core.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/keystone_qos.c | 129 |
2 files changed, 142 insertions, 13 deletions
diff --git a/drivers/net/ethernet/ti/keystone_net_core.c b/drivers/net/ethernet/ti/keystone_net_core.c index 56c3493a72a..6bfe350cb65 100644 --- a/drivers/net/ethernet/ti/keystone_net_core.c +++ b/drivers/net/ethernet/ti/keystone_net_core.c | |||
@@ -1337,7 +1337,12 @@ int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) | |||
1337 | { | 1337 | { |
1338 | struct dma_keystone_info config; | 1338 | struct dma_keystone_info config; |
1339 | dma_cap_mask_t mask; | 1339 | dma_cap_mask_t mask; |
1340 | int ret; | 1340 | int ret, queue_depth; |
1341 | |||
1342 | queue_depth = tx_pipe->dma_queue_depth; | ||
1343 | tx_pipe->dma_pause_threshold = (MAX_SKB_FRAGS < (queue_depth / 4)) ? | ||
1344 | MAX_SKB_FRAGS : (queue_depth / 4); | ||
1345 | tx_pipe->dma_resume_threshold = tx_pipe->dma_pause_threshold; | ||
1341 | 1346 | ||
1342 | dma_cap_zero(mask); | 1347 | dma_cap_zero(mask); |
1343 | dma_cap_set(DMA_SLAVE, mask); | 1348 | dma_cap_set(DMA_SLAVE, mask); |
@@ -1353,7 +1358,7 @@ int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) | |||
1353 | 1358 | ||
1354 | memset(&config, 0, sizeof(config)); | 1359 | memset(&config, 0, sizeof(config)); |
1355 | config.direction = DMA_MEM_TO_DEV; | 1360 | config.direction = DMA_MEM_TO_DEV; |
1356 | config.tx_queue_depth = tx_pipe->dma_queue_depth; | 1361 | config.tx_queue_depth = queue_depth; |
1357 | ret = dma_keystone_config(tx_pipe->dma_channel, &config); | 1362 | ret = dma_keystone_config(tx_pipe->dma_channel, &config); |
1358 | if (ret) { | 1363 | if (ret) { |
1359 | dev_err(tx_pipe->netcp_priv->dev, | 1364 | dev_err(tx_pipe->netcp_priv->dev, |
@@ -1365,14 +1370,16 @@ int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe) | |||
1365 | } | 1370 | } |
1366 | 1371 | ||
1367 | tx_pipe->dma_queue = dma_get_tx_queue(tx_pipe->dma_channel); | 1372 | tx_pipe->dma_queue = dma_get_tx_queue(tx_pipe->dma_channel); |
1368 | atomic_set(&tx_pipe->dma_poll_count, tx_pipe->dma_queue_depth); | 1373 | atomic_set(&tx_pipe->dma_poll_count, queue_depth); |
1369 | netcp_set_txpipe_state(tx_pipe, TX_STATE_INTERRUPT); | 1374 | netcp_set_txpipe_state(tx_pipe, TX_STATE_INTERRUPT); |
1370 | napi_enable(&tx_pipe->dma_poll_napi); | 1375 | napi_enable(&tx_pipe->dma_poll_napi); |
1371 | dma_set_notify(tx_pipe->dma_channel, netcp_tx_notify, tx_pipe); | 1376 | dma_set_notify(tx_pipe->dma_channel, netcp_tx_notify, tx_pipe); |
1372 | 1377 | ||
1373 | 1378 | ||
1374 | dev_dbg(tx_pipe->netcp_priv->dev, "opened tx pipe %s\n", | 1379 | dev_dbg(tx_pipe->netcp_priv->dev, |
1375 | tx_pipe->dma_chan_name); | 1380 | "opened tx pipe %s, depth %d, pause/resume %d/%d\n", |
1381 | tx_pipe->dma_chan_name, queue_depth, | ||
1382 | tx_pipe->dma_pause_threshold, tx_pipe->dma_resume_threshold); | ||
1376 | return 0; | 1383 | return 0; |
1377 | } | 1384 | } |
1378 | EXPORT_SYMBOL(netcp_txpipe_open); | 1385 | EXPORT_SYMBOL(netcp_txpipe_open); |
@@ -1388,17 +1395,12 @@ int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe, | |||
1388 | tx_pipe->dma_chan_name = chan_name; | 1395 | tx_pipe->dma_chan_name = chan_name; |
1389 | tx_pipe->dma_queue_depth = queue_depth; | 1396 | tx_pipe->dma_queue_depth = queue_depth; |
1390 | 1397 | ||
1391 | tx_pipe->dma_pause_threshold = (MAX_SKB_FRAGS < (queue_depth / 4)) ? | ||
1392 | MAX_SKB_FRAGS : (queue_depth / 4); | ||
1393 | tx_pipe->dma_resume_threshold = tx_pipe->dma_pause_threshold; | ||
1394 | |||
1395 | netcp_set_txpipe_state(tx_pipe, TX_STATE_INVALID); | 1398 | netcp_set_txpipe_state(tx_pipe, TX_STATE_INVALID); |
1396 | netif_napi_add(netcp_priv->ndev, &tx_pipe->dma_poll_napi, | 1399 | netif_napi_add(netcp_priv->ndev, &tx_pipe->dma_poll_napi, |
1397 | netcp_tx_poll, NETCP_NAPI_WEIGHT_TX); | 1400 | netcp_tx_poll, NETCP_NAPI_WEIGHT_TX); |
1398 | 1401 | ||
1399 | dev_dbg(tx_pipe->netcp_priv->dev, "initialized tx pipe %s, %d/%d\n", | 1402 | dev_dbg(tx_pipe->netcp_priv->dev, "initialized tx pipe %s\n", |
1400 | tx_pipe->dma_chan_name, tx_pipe->dma_pause_threshold, | 1403 | tx_pipe->dma_chan_name); |
1401 | tx_pipe->dma_resume_threshold); | ||
1402 | return 0; | 1404 | return 0; |
1403 | } | 1405 | } |
1404 | EXPORT_SYMBOL(netcp_txpipe_init); | 1406 | EXPORT_SYMBOL(netcp_txpipe_init); |
diff --git a/drivers/net/ethernet/ti/keystone_qos.c b/drivers/net/ethernet/ti/keystone_qos.c index 18366346865..062f733f9e3 100644 --- a/drivers/net/ethernet/ti/keystone_qos.c +++ b/drivers/net/ethernet/ti/keystone_qos.c | |||
@@ -41,6 +41,7 @@ struct qos_channel { | |||
41 | const char *tx_chan_name; | 41 | const char *tx_chan_name; |
42 | u32 tx_queue_depth; | 42 | u32 tx_queue_depth; |
43 | struct netcp_tx_pipe tx_pipe; | 43 | struct netcp_tx_pipe tx_pipe; |
44 | struct kobject kobj; | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | struct qos_device { | 47 | struct qos_device { |
@@ -48,16 +49,106 @@ struct qos_device { | |||
48 | struct device *dev; | 49 | struct device *dev; |
49 | struct device_node *node; | 50 | struct device_node *node; |
50 | u32 multi_if; | 51 | u32 multi_if; |
52 | struct kobject kobj; | ||
51 | }; | 53 | }; |
52 | 54 | ||
53 | struct qos_intf { | 55 | struct qos_intf { |
56 | struct qos_device *qdev; | ||
54 | struct net_device *ndev; | 57 | struct net_device *ndev; |
55 | struct device *dev; | 58 | struct device *dev; |
59 | struct kobject kobj; | ||
56 | int num_channels; | 60 | int num_channels; |
57 | int max_channels; | 61 | int max_channels; |
58 | struct qos_channel channels[1]; | 62 | struct qos_channel channels[1]; |
63 | /* NB: channels is allocated dynamically */ | ||
59 | }; | 64 | }; |
60 | 65 | ||
66 | /* | ||
67 | * Sysfs stuff related to QoS TX Channels | ||
68 | */ | ||
69 | #define kobj_to_qchan(kobj) container_of(kobj, struct qos_channel, kobj) | ||
70 | |||
71 | static ssize_t qos_txchan_show(struct kobject *kobj, | ||
72 | struct kobj_attribute *attr, | ||
73 | char *buf) | ||
74 | { | ||
75 | struct qos_channel *qos_chan = kobj_to_qchan(kobj); | ||
76 | return snprintf(buf, PAGE_SIZE, "%s\n", qos_chan->tx_chan_name); | ||
77 | } | ||
78 | |||
79 | struct kobj_attribute qos_txchan_attr = | ||
80 | __ATTR(tx-channel, S_IRUGO, qos_txchan_show, NULL); | ||
81 | |||
82 | |||
83 | static ssize_t qos_txdepth_show(struct kobject *kobj, | ||
84 | struct kobj_attribute *attr, | ||
85 | char *buf) | ||
86 | { | ||
87 | struct qos_channel *qos_chan = kobj_to_qchan(kobj); | ||
88 | return snprintf(buf, PAGE_SIZE, "%u\n", qos_chan->tx_queue_depth); | ||
89 | } | ||
90 | |||
91 | static ssize_t qos_txdepth_store(struct kobject *kobj, | ||
92 | struct kobj_attribute *attr, | ||
93 | const char *buf, size_t count) | ||
94 | { | ||
95 | struct qos_channel *qos_chan = kobj_to_qchan(kobj); | ||
96 | struct netcp_tx_pipe *tx_pipe = &qos_chan->tx_pipe; | ||
97 | unsigned int val; | ||
98 | |||
99 | if (kstrtouint(buf, 0, &val) < 0) | ||
100 | return -EINVAL; | ||
101 | |||
102 | qos_chan->tx_queue_depth = val; | ||
103 | tx_pipe->dma_queue_depth = val; | ||
104 | |||
105 | return count; | ||
106 | } | ||
107 | |||
108 | struct kobj_attribute qos_txdepth_attr = | ||
109 | __ATTR(tx_queue_depth, S_IRUGO | S_IWUSR, | ||
110 | qos_txdepth_show, qos_txdepth_store); | ||
111 | |||
112 | static struct attribute *qos_txchan_attrs[] = { | ||
113 | &qos_txchan_attr.attr, | ||
114 | &qos_txdepth_attr.attr, | ||
115 | NULL | ||
116 | }; | ||
117 | |||
118 | static struct kobj_type qos_chan_ktype = { | ||
119 | .sysfs_ops = &kobj_sysfs_ops, | ||
120 | .default_attrs = qos_txchan_attrs, | ||
121 | }; | ||
122 | |||
123 | /* Sysfs stuff related to QoS Interfaces */ | ||
124 | static struct kobj_type qos_intf_ktype = { | ||
125 | .sysfs_ops = &kobj_sysfs_ops, | ||
126 | }; | ||
127 | |||
128 | /* Sysfs stuff related to QoS Instances */ | ||
129 | #define kobj_to_qdev(kobj) container_of(kobj, struct qos_device, kobj) | ||
130 | static ssize_t qos_multi_if_show(struct kobject *kobj, | ||
131 | struct kobj_attribute *attr, | ||
132 | char *buf) | ||
133 | { | ||
134 | struct qos_device *qos_dev = kobj_to_qdev(kobj); | ||
135 | return snprintf(buf, PAGE_SIZE, "%u\n", qos_dev->multi_if); | ||
136 | } | ||
137 | |||
138 | struct kobj_attribute qos_multi_if_attr = | ||
139 | __ATTR(multi-interface, S_IRUGO, qos_multi_if_show, NULL); | ||
140 | |||
141 | static struct attribute *qos_inst_attrs[] = { | ||
142 | &qos_multi_if_attr.attr, | ||
143 | NULL | ||
144 | }; | ||
145 | |||
146 | static struct kobj_type qos_inst_ktype = { | ||
147 | .sysfs_ops = &kobj_sysfs_ops, | ||
148 | .default_attrs = qos_inst_attrs, | ||
149 | }; | ||
150 | |||
151 | |||
61 | static int qos_tx_hook(int order, void *data, struct netcp_packet *p_info) | 152 | static int qos_tx_hook(int order, void *data, struct netcp_packet *p_info) |
62 | { | 153 | { |
63 | struct qos_intf *qos_intf = data; | 154 | struct qos_intf *qos_intf = data; |
@@ -148,6 +239,19 @@ static int init_channel(struct qos_intf *qos_intf, | |||
148 | } | 239 | } |
149 | dev_dbg(qos_intf->dev, "tx_queue_depth %u\n", qchan->tx_queue_depth); | 240 | dev_dbg(qos_intf->dev, "tx_queue_depth %u\n", qchan->tx_queue_depth); |
150 | 241 | ||
242 | /* Create the per-channel entry and attributes */ | ||
243 | ret = kobject_init_and_add(&qchan->kobj, &qos_chan_ktype, | ||
244 | kobject_get(&qos_intf->kobj), node->name); | ||
245 | if (ret) { | ||
246 | dev_err(qos_intf->dev, | ||
247 | "failed to create %s/%s/%s sysfs entry\n", | ||
248 | qos_intf->qdev->kobj.name, qos_intf->kobj.name, | ||
249 | node->name); | ||
250 | kobject_put(&qchan->kobj); | ||
251 | kobject_put(&qos_intf->kobj); | ||
252 | return ret; | ||
253 | } | ||
254 | |||
151 | return 0; | 255 | return 0; |
152 | } | 256 | } |
153 | 257 | ||
@@ -173,6 +277,7 @@ static int qos_attach(void *inst_priv, struct net_device *ndev, | |||
173 | } | 277 | } |
174 | qos_intf->max_channels = max_channels; | 278 | qos_intf->max_channels = max_channels; |
175 | 279 | ||
280 | qos_intf->qdev = qos_dev; | ||
176 | qos_intf->ndev = ndev; | 281 | qos_intf->ndev = ndev; |
177 | qos_intf->dev = qos_dev->dev; | 282 | qos_intf->dev = qos_dev->dev; |
178 | 283 | ||
@@ -190,6 +295,17 @@ static int qos_attach(void *inst_priv, struct net_device *ndev, | |||
190 | goto exit; | 295 | goto exit; |
191 | } | 296 | } |
192 | 297 | ||
298 | /* Create the per-interface sysfs entry */ | ||
299 | ret = kobject_init_and_add(&qos_intf->kobj, &qos_intf_ktype, | ||
300 | kobject_get(&qos_intf->qdev->kobj), node_name); | ||
301 | if (ret) { | ||
302 | dev_err(qos_intf->dev, "failed to create %s/%s sysfs entry\n", | ||
303 | qos_intf->qdev->kobj.name, node_name); | ||
304 | kobject_put(&qos_intf->kobj); | ||
305 | kobject_put(&qos_intf->qdev->kobj); | ||
306 | goto exit; | ||
307 | } | ||
308 | |||
193 | qos_intf->num_channels = 0; | 309 | qos_intf->num_channels = 0; |
194 | for_each_child_of_node(interface, channel) { | 310 | for_each_child_of_node(interface, channel) { |
195 | if (qos_intf->num_channels >= max_channels) { | 311 | if (qos_intf->num_channels >= max_channels) { |
@@ -245,7 +361,7 @@ static int qos_probe(struct netcp_device *netcp_device, | |||
245 | { | 361 | { |
246 | struct qos_device *qos_dev; | 362 | struct qos_device *qos_dev; |
247 | int ret = 0; | 363 | int ret = 0; |
248 | 364 | ||
249 | qos_dev = devm_kzalloc(dev, sizeof(struct qos_device), GFP_KERNEL); | 365 | qos_dev = devm_kzalloc(dev, sizeof(struct qos_device), GFP_KERNEL); |
250 | if (!qos_dev) { | 366 | if (!qos_dev) { |
251 | dev_err(dev, "memory allocation failed\n"); | 367 | dev_err(dev, "memory allocation failed\n"); |
@@ -266,6 +382,17 @@ static int qos_probe(struct netcp_device *netcp_device, | |||
266 | if (of_find_property(node, "multi-interface", NULL)) | 382 | if (of_find_property(node, "multi-interface", NULL)) |
267 | qos_dev->multi_if = 1; | 383 | qos_dev->multi_if = 1; |
268 | 384 | ||
385 | /* Create the per-instance sysfs entry */ | ||
386 | ret = kobject_init_and_add(&qos_dev->kobj, &qos_inst_ktype, | ||
387 | kobject_get(&dev->kobj), node->name); | ||
388 | if (ret) { | ||
389 | dev_err(dev, "failed to create %s sysfs entry\n", | ||
390 | node->name); | ||
391 | kobject_put(&qos_dev->kobj); | ||
392 | kobject_put(&dev->kobj); | ||
393 | goto exit; | ||
394 | } | ||
395 | |||
269 | return 0; | 396 | return 0; |
270 | 397 | ||
271 | exit: | 398 | exit: |