aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReece R. Pollack2015-02-20 17:36:40 -0600
committerReece R. Pollack2015-02-27 14:43:29 -0600
commit2f549b1ea2418bc30bbfd624b2f4fd2255fb3e82 (patch)
tree99b004adf2be12583a59ef1102d45c6669a10e8b
parent639ea778eadd4f5b0a85acac872f50085826d511 (diff)
downloadlinux-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.c26
-rw-r--r--drivers/net/ethernet/ti/keystone_qos.c129
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}
1378EXPORT_SYMBOL(netcp_txpipe_open); 1385EXPORT_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}
1404EXPORT_SYMBOL(netcp_txpipe_init); 1406EXPORT_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
46struct qos_device { 47struct 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
53struct qos_intf { 55struct 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
71static 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
79struct kobj_attribute qos_txchan_attr =
80 __ATTR(tx-channel, S_IRUGO, qos_txchan_show, NULL);
81
82
83static 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
91static 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
108struct kobj_attribute qos_txdepth_attr =
109 __ATTR(tx_queue_depth, S_IRUGO | S_IWUSR,
110 qos_txdepth_show, qos_txdepth_store);
111
112static struct attribute *qos_txchan_attrs[] = {
113 &qos_txchan_attr.attr,
114 &qos_txdepth_attr.attr,
115 NULL
116};
117
118static 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 */
124static 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)
130static 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
138struct kobj_attribute qos_multi_if_attr =
139 __ATTR(multi-interface, S_IRUGO, qos_multi_if_show, NULL);
140
141static struct attribute *qos_inst_attrs[] = {
142 &qos_multi_if_attr.attr,
143 NULL
144};
145
146static struct kobj_type qos_inst_ktype = {
147 .sysfs_ops = &kobj_sysfs_ops,
148 .default_attrs = qos_inst_attrs,
149};
150
151
61static int qos_tx_hook(int order, void *data, struct netcp_packet *p_info) 152static 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
271exit: 398exit: