aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/caif/caif_hsi.c
diff options
context:
space:
mode:
authorSjur Brændeland <sjur.brandeland@stericsson.com>2012-06-25 03:49:41 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-25 19:44:12 -0400
commitc41254006377842013922fb1e407391f24c59522 (patch)
tree9ed40b855fe2ad5a9808cee6e622acd3935400b4 /drivers/net/caif/caif_hsi.c
parent5051c94bb3998ff24bf07ae3b72dca30f85962f8 (diff)
caif-hsi: Add rtnl support
Add RTNL support for managing the caif hsi interface. The HSI HW interface is no longer registering as a device, instead we use symbol_get to get hold of the HSI API. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/caif/caif_hsi.c')
-rw-r--r--drivers/net/caif/caif_hsi.c226
1 files changed, 137 insertions, 89 deletions
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index d80759e58532..a14f85c0f0e8 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -20,7 +20,7 @@
20#include <linux/sched.h> 20#include <linux/sched.h>
21#include <linux/if_arp.h> 21#include <linux/if_arp.h>
22#include <linux/timer.h> 22#include <linux/timer.h>
23#include <linux/rtnetlink.h> 23#include <net/rtnetlink.h>
24#include <linux/pkt_sched.h> 24#include <linux/pkt_sched.h>
25#include <net/caif/caif_layer.h> 25#include <net/caif/caif_layer.h>
26#include <net/caif/caif_hsi.h> 26#include <net/caif/caif_hsi.h>
@@ -79,7 +79,6 @@ MODULE_PARM_DESC(hsi_low_threshold, "HSI high threshold (FLOW ON).");
79#define HIGH_WATER_MARK hsi_high_threshold 79#define HIGH_WATER_MARK hsi_high_threshold
80 80
81static LIST_HEAD(cfhsi_list); 81static LIST_HEAD(cfhsi_list);
82static spinlock_t cfhsi_list_lock;
83 82
84static void cfhsi_inactivity_tout(unsigned long arg) 83static void cfhsi_inactivity_tout(unsigned long arg)
85{ 84{
@@ -1148,42 +1147,6 @@ static void cfhsi_setup(struct net_device *dev)
1148 cfhsi->ndev = dev; 1147 cfhsi->ndev = dev;
1149} 1148}
1150 1149
1151int cfhsi_probe(struct platform_device *pdev)
1152{
1153 struct cfhsi *cfhsi = NULL;
1154 struct net_device *ndev;
1155
1156 int res;
1157
1158 ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup);
1159 if (!ndev)
1160 return -ENODEV;
1161
1162 cfhsi = netdev_priv(ndev);
1163 cfhsi->ndev = ndev;
1164 cfhsi->pdev = pdev;
1165
1166 /* Assign the HSI device. */
1167 cfhsi->dev = pdev->dev.platform_data;
1168
1169 /* Assign the driver to this HSI device. */
1170 cfhsi->dev->drv = &cfhsi->drv;
1171
1172 /* Register network device. */
1173 res = register_netdev(ndev);
1174 if (res) {
1175 dev_err(&ndev->dev, "%s: Registration error: %d.\n",
1176 __func__, res);
1177 free_netdev(ndev);
1178 }
1179 /* Add CAIF HSI device to list. */
1180 spin_lock(&cfhsi_list_lock);
1181 list_add_tail(&cfhsi->list, &cfhsi_list);
1182 spin_unlock(&cfhsi_list_lock);
1183
1184 return res;
1185}
1186
1187static int cfhsi_open(struct net_device *ndev) 1150static int cfhsi_open(struct net_device *ndev)
1188{ 1151{
1189 struct cfhsi *cfhsi = netdev_priv(ndev); 1152 struct cfhsi *cfhsi = netdev_priv(ndev);
@@ -1364,85 +1327,170 @@ static int cfhsi_close(struct net_device *ndev)
1364 return 0; 1327 return 0;
1365} 1328}
1366 1329
1330static void cfhsi_uninit(struct net_device *dev)
1331{
1332 struct cfhsi *cfhsi = netdev_priv(dev);
1333 ASSERT_RTNL();
1334 symbol_put(cfhsi_get_device);
1335 list_del(&cfhsi->list);
1336}
1337
1367static const struct net_device_ops cfhsi_ops = { 1338static const struct net_device_ops cfhsi_ops = {
1339 .ndo_uninit = cfhsi_uninit,
1368 .ndo_open = cfhsi_open, 1340 .ndo_open = cfhsi_open,
1369 .ndo_stop = cfhsi_close, 1341 .ndo_stop = cfhsi_close,
1370 .ndo_start_xmit = cfhsi_xmit 1342 .ndo_start_xmit = cfhsi_xmit
1371}; 1343};
1372 1344
1373int cfhsi_remove(struct platform_device *pdev) 1345static void cfhsi_netlink_parms(struct nlattr *data[], struct cfhsi *cfhsi)
1374{ 1346{
1375 struct list_head *list_node; 1347 int i;
1376 struct list_head *n;
1377 struct cfhsi *cfhsi = NULL;
1378 struct cfhsi_dev *dev;
1379 1348
1380 dev = (struct cfhsi_dev *)pdev->dev.platform_data; 1349 if (!data) {
1381 spin_lock(&cfhsi_list_lock); 1350 pr_debug("no params data found\n");
1382 list_for_each_safe(list_node, n, &cfhsi_list) { 1351 return;
1383 cfhsi = list_entry(list_node, struct cfhsi, list);
1384 /* Find the corresponding device. */
1385 if (cfhsi->dev == dev) {
1386 /* Remove from list. */
1387 list_del(list_node);
1388 spin_unlock(&cfhsi_list_lock);
1389 return 0;
1390 }
1391 } 1352 }
1392 spin_unlock(&cfhsi_list_lock); 1353
1393 return -ENODEV; 1354 i = __IFLA_CAIF_HSI_INACTIVITY_TOUT;
1355 if (data[i])
1356 inactivity_timeout = nla_get_u32(data[i]);
1357
1358 i = __IFLA_CAIF_HSI_AGGREGATION_TOUT;
1359 if (data[i])
1360 aggregation_timeout = nla_get_u32(data[i]);
1361
1362 i = __IFLA_CAIF_HSI_HEAD_ALIGN;
1363 if (data[i])
1364 hsi_head_align = nla_get_u32(data[i]);
1365
1366 i = __IFLA_CAIF_HSI_TAIL_ALIGN;
1367 if (data[i])
1368 hsi_tail_align = nla_get_u32(data[i]);
1369
1370 i = __IFLA_CAIF_HSI_QHIGH_WATERMARK;
1371 if (data[i])
1372 hsi_high_threshold = nla_get_u32(data[i]);
1373}
1374
1375static int caif_hsi_changelink(struct net_device *dev, struct nlattr *tb[],
1376 struct nlattr *data[])
1377{
1378 cfhsi_netlink_parms(data, netdev_priv(dev));
1379 netdev_state_change(dev);
1380 return 0;
1394} 1381}
1395 1382
1396struct platform_driver cfhsi_plat_drv = { 1383static const struct nla_policy caif_hsi_policy[__IFLA_CAIF_HSI_MAX + 1] = {
1397 .probe = cfhsi_probe, 1384 [__IFLA_CAIF_HSI_INACTIVITY_TOUT] = { .type = NLA_U32, .len = 4 },
1398 .remove = cfhsi_remove, 1385 [__IFLA_CAIF_HSI_AGGREGATION_TOUT] = { .type = NLA_U32, .len = 4 },
1399 .driver = { 1386 [__IFLA_CAIF_HSI_HEAD_ALIGN] = { .type = NLA_U32, .len = 4 },
1400 .name = "cfhsi", 1387 [__IFLA_CAIF_HSI_TAIL_ALIGN] = { .type = NLA_U32, .len = 4 },
1401 .owner = THIS_MODULE, 1388 [__IFLA_CAIF_HSI_QHIGH_WATERMARK] = { .type = NLA_U32, .len = 4 },
1402 }, 1389 [__IFLA_CAIF_HSI_QLOW_WATERMARK] = { .type = NLA_U32, .len = 4 },
1403}; 1390};
1404 1391
1405static void __exit cfhsi_exit_module(void) 1392static size_t caif_hsi_get_size(const struct net_device *dev)
1393{
1394 int i;
1395 size_t s = 0;
1396 for (i = __IFLA_CAIF_HSI_UNSPEC + 1; i < __IFLA_CAIF_HSI_MAX; i++)
1397 s += nla_total_size(caif_hsi_policy[i].len);
1398 return s;
1399}
1400
1401static int caif_hsi_fill_info(struct sk_buff *skb, const struct net_device *dev)
1402{
1403 if (nla_put_u32(skb, __IFLA_CAIF_HSI_INACTIVITY_TOUT,
1404 inactivity_timeout) ||
1405 nla_put_u32(skb, __IFLA_CAIF_HSI_AGGREGATION_TOUT,
1406 aggregation_timeout) ||
1407 nla_put_u32(skb, __IFLA_CAIF_HSI_HEAD_ALIGN, hsi_head_align) ||
1408 nla_put_u32(skb, __IFLA_CAIF_HSI_TAIL_ALIGN, hsi_tail_align) ||
1409 nla_put_u32(skb, __IFLA_CAIF_HSI_QHIGH_WATERMARK,
1410 hsi_high_threshold) ||
1411 nla_put_u32(skb, __IFLA_CAIF_HSI_QLOW_WATERMARK,
1412 hsi_low_threshold))
1413 return -EMSGSIZE;
1414
1415 return 0;
1416}
1417
1418static int caif_hsi_newlink(struct net *src_net, struct net_device *dev,
1419 struct nlattr *tb[], struct nlattr *data[])
1406{ 1420{
1407 struct list_head *list_node;
1408 struct list_head *n;
1409 struct cfhsi *cfhsi = NULL; 1421 struct cfhsi *cfhsi = NULL;
1422 struct platform_device *(*get_dev)(void);
1410 1423
1411 spin_lock(&cfhsi_list_lock); 1424 ASSERT_RTNL();
1412 list_for_each_safe(list_node, n, &cfhsi_list) { 1425
1413 cfhsi = list_entry(list_node, struct cfhsi, list); 1426 cfhsi = netdev_priv(dev);
1427 cfhsi_netlink_parms(data, cfhsi);
1428 dev_net_set(cfhsi->ndev, src_net);
1429
1430 get_dev = symbol_get(cfhsi_get_device);
1431 if (!get_dev) {
1432 pr_err("%s: failed to get the cfhsi device symbol\n", __func__);
1433 return -ENODEV;
1434 }
1435
1436 /* Assign the HSI device. */
1437 cfhsi->pdev = (*get_dev)();
1438 if (!cfhsi->pdev) {
1439 pr_err("%s: failed to get the cfhsi device\n", __func__);
1440 goto err;
1441 }
1414 1442
1415 /* Remove from list. */ 1443 /* Assign the HSI device. */
1416 list_del(list_node); 1444 cfhsi->dev = cfhsi->pdev->dev.platform_data;
1417 spin_unlock(&cfhsi_list_lock); 1445
1446 /* Assign the driver to this HSI device. */
1447 cfhsi->dev->drv = &cfhsi->drv;
1418 1448
1419 unregister_netdevice(cfhsi->ndev); 1449 if (register_netdevice(dev)) {
1450 pr_warn("%s: device rtml registration failed\n", __func__);
1451 goto err;
1420 1452
1421 spin_lock(&cfhsi_list_lock);
1422 } 1453 }
1423 spin_unlock(&cfhsi_list_lock); 1454 /* Add CAIF HSI device to list. */
1455 list_add_tail(&cfhsi->list, &cfhsi_list);
1424 1456
1425 /* Unregister platform driver. */ 1457 return 0;
1426 platform_driver_unregister(&cfhsi_plat_drv); 1458err:
1459 symbol_put(cfhsi_get_device);
1460 return -ENODEV;
1427} 1461}
1428 1462
1429static int __init cfhsi_init_module(void) 1463static struct rtnl_link_ops caif_hsi_link_ops __read_mostly = {
1464 .kind = "cfhsi",
1465 .priv_size = sizeof(struct cfhsi),
1466 .setup = cfhsi_setup,
1467 .maxtype = __IFLA_CAIF_HSI_MAX,
1468 .policy = caif_hsi_policy,
1469 .newlink = caif_hsi_newlink,
1470 .changelink = caif_hsi_changelink,
1471 .get_size = caif_hsi_get_size,
1472 .fill_info = caif_hsi_fill_info,
1473};
1474
1475static void __exit cfhsi_exit_module(void)
1430{ 1476{
1431 int result; 1477 struct list_head *list_node;
1478 struct list_head *n;
1479 struct cfhsi *cfhsi;
1432 1480
1433 /* Initialize spin lock. */ 1481 rtnl_link_unregister(&caif_hsi_link_ops);
1434 spin_lock_init(&cfhsi_list_lock);
1435 1482
1436 /* Register platform driver. */ 1483 rtnl_lock();
1437 result = platform_driver_register(&cfhsi_plat_drv); 1484 list_for_each_safe(list_node, n, &cfhsi_list) {
1438 if (result) { 1485 cfhsi = list_entry(list_node, struct cfhsi, list);
1439 printk(KERN_ERR "Could not register platform HSI driver: %d.\n", 1486 unregister_netdev(cfhsi->ndev);
1440 result);
1441 goto err_dev_register;
1442 } 1487 }
1488 rtnl_unlock();
1489}
1443 1490
1444 err_dev_register: 1491static int __init cfhsi_init_module(void)
1445 return result; 1492{
1493 return rtnl_link_register(&caif_hsi_link_ops);
1446} 1494}
1447 1495
1448module_init(cfhsi_init_module); 1496module_init(cfhsi_init_module);