aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/link.c
diff options
context:
space:
mode:
authorJon Maloy <jon.maloy@ericsson.com>2019-08-15 10:42:50 -0400
committerDavid S. Miller <davem@davemloft.net>2019-08-18 17:01:07 -0400
commite654f9f53b45fde3fcc8051830b212c7a8f36148 (patch)
tree1b3b3af06442bae94101ca20f1c0b6ca06d54e44 /net/tipc/link.c
parent10086b345385bc1ca67b260aff236e742e2e630e (diff)
tipc: clean up skb list lock handling on send path
The policy for handling the skb list locks on the send and receive paths is simple. - On the send path we never need to grab the lock on the 'xmitq' list when the destination is an exernal node. - On the receive path we always need to grab the lock on the 'inputq' list, irrespective of source node. However, when transmitting node local messages those will eventually end up on the receive path of a local socket, meaning that the argument 'xmitq' in tipc_node_xmit() will become the 'ínputq' argument in the function tipc_sk_rcv(). This has been handled by always initializing the spinlock of the 'xmitq' list at message creation, just in case it may end up on the receive path later, and despite knowing that the lock in most cases never will be used. This approach is inaccurate and confusing, and has also concealed the fact that the stated 'no lock grabbing' policy for the send path is violated in some cases. We now clean up this by never initializing the lock at message creation, instead doing this at the moment we find that the message actually will enter the receive path. At the same time we fix the four locations where we incorrectly access the spinlock on the send/error path. This patch also reverts commit d12cffe9329f ("tipc: ensure head->lock is initialised") which has now become redundant. CC: Eric Dumazet <edumazet@google.com> Reported-by: Chris Packham <chris.packham@alliedtelesis.co.nz> Acked-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r--net/tipc/link.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index dd3155b14654..289e848084ac 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -959,7 +959,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
959 pr_warn("Too large msg, purging xmit list %d %d %d %d %d!\n", 959 pr_warn("Too large msg, purging xmit list %d %d %d %d %d!\n",
960 skb_queue_len(list), msg_user(hdr), 960 skb_queue_len(list), msg_user(hdr),
961 msg_type(hdr), msg_size(hdr), mtu); 961 msg_type(hdr), msg_size(hdr), mtu);
962 skb_queue_purge(list); 962 __skb_queue_purge(list);
963 return -EMSGSIZE; 963 return -EMSGSIZE;
964 } 964 }
965 965
@@ -988,7 +988,7 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
988 if (likely(skb_queue_len(transmq) < maxwin)) { 988 if (likely(skb_queue_len(transmq) < maxwin)) {
989 _skb = skb_clone(skb, GFP_ATOMIC); 989 _skb = skb_clone(skb, GFP_ATOMIC);
990 if (!_skb) { 990 if (!_skb) {
991 skb_queue_purge(list); 991 __skb_queue_purge(list);
992 return -ENOBUFS; 992 return -ENOBUFS;
993 } 993 }
994 __skb_dequeue(list); 994 __skb_dequeue(list);
@@ -1668,7 +1668,7 @@ void tipc_link_create_dummy_tnl_msg(struct tipc_link *l,
1668 struct sk_buff *skb; 1668 struct sk_buff *skb;
1669 u32 dnode = l->addr; 1669 u32 dnode = l->addr;
1670 1670
1671 skb_queue_head_init(&tnlq); 1671 __skb_queue_head_init(&tnlq);
1672 skb = tipc_msg_create(TUNNEL_PROTOCOL, FAILOVER_MSG, 1672 skb = tipc_msg_create(TUNNEL_PROTOCOL, FAILOVER_MSG,
1673 INT_H_SIZE, BASIC_H_SIZE, 1673 INT_H_SIZE, BASIC_H_SIZE,
1674 dnode, onode, 0, 0, 0); 1674 dnode, onode, 0, 0, 0);
@@ -1708,9 +1708,9 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
1708 if (!tnl) 1708 if (!tnl)
1709 return; 1709 return;
1710 1710
1711 skb_queue_head_init(&tnlq); 1711 __skb_queue_head_init(&tnlq);
1712 skb_queue_head_init(&tmpxq); 1712 __skb_queue_head_init(&tmpxq);
1713 skb_queue_head_init(&frags); 1713 __skb_queue_head_init(&frags);
1714 1714
1715 /* At least one packet required for safe algorithm => add dummy */ 1715 /* At least one packet required for safe algorithm => add dummy */
1716 skb = tipc_msg_create(TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG, 1716 skb = tipc_msg_create(TIPC_LOW_IMPORTANCE, TIPC_DIRECT_MSG,
@@ -1720,7 +1720,7 @@ void tipc_link_tnl_prepare(struct tipc_link *l, struct tipc_link *tnl,
1720 pr_warn("%sunable to create tunnel packet\n", link_co_err); 1720 pr_warn("%sunable to create tunnel packet\n", link_co_err);
1721 return; 1721 return;
1722 } 1722 }
1723 skb_queue_tail(&tnlq, skb); 1723 __skb_queue_tail(&tnlq, skb);
1724 tipc_link_xmit(l, &tnlq, &tmpxq); 1724 tipc_link_xmit(l, &tnlq, &tmpxq);
1725 __skb_queue_purge(&tmpxq); 1725 __skb_queue_purge(&tmpxq);
1726 1726
>, 2550000, 2600000, 2650000, 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3200000, 3300000, }; static const unsigned int LDO1_VSEL_table[] = { 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1400000, 1500000, 1600000, 1800000, 2500000, 2750000, 2800000, 3000000, 3100000, 3300000, }; /* The voltage mapping table for LDO2 is the same as VDCDCx */ #define LDO2_VSEL_table VDCDCx_VSEL_table struct tps_info { const char *name; u8 table_len; const unsigned int *table; /* Does DCDC high or the low register defines output voltage? */ bool defdcdc_default; }; static struct tps_info tps6507x_pmic_regs[] = { { .name = "VDCDC1", .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "VDCDC2", .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "VDCDC3", .table_len = ARRAY_SIZE(VDCDCx_VSEL_table), .table = VDCDCx_VSEL_table, }, { .name = "LDO1", .table_len = ARRAY_SIZE(LDO1_VSEL_table), .table = LDO1_VSEL_table, }, { .name = "LDO2", .table_len = ARRAY_SIZE(LDO2_VSEL_table), .table = LDO2_VSEL_table, }, }; struct tps6507x_pmic { struct regulator_desc desc[TPS6507X_NUM_REGULATOR]; struct tps6507x_dev *mfd; struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR]; struct tps_info *info[TPS6507X_NUM_REGULATOR]; struct mutex io_lock; }; static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg) { u8 val; int err; err = tps->mfd->read_dev(tps->mfd, reg, 1, &val); if (err) return err; return val; } static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val) { return tps->mfd->write_dev(tps->mfd, reg, 1, &val); } static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) { int err, data; mutex_lock(&tps->io_lock); data = tps6507x_pmic_read(tps, reg); if (data < 0) { dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); err = data; goto out; } data |= mask; err = tps6507x_pmic_write(tps, reg, data); if (err) dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); out: mutex_unlock(&tps->io_lock); return err; } static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask) { int err, data; mutex_lock(&tps->io_lock); data = tps6507x_pmic_read(tps, reg); if (data < 0) { dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); err = data; goto out; } data &= ~mask; err = tps6507x_pmic_write(tps, reg, data); if (err) dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); out: mutex_unlock(&tps->io_lock); return err; } static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg) { int data; mutex_lock(&tps->io_lock); data = tps6507x_pmic_read(tps, reg); if (data < 0) dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg); mutex_unlock(&tps->io_lock); return data; } static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val) { int err; mutex_lock(&tps->io_lock); err = tps6507x_pmic_write(tps, reg, val); if (err < 0) dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg); mutex_unlock(&tps->io_lock); return err; } static int tps6507x_pmic_is_enabled(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, rid = rdev_get_id(dev); u8 shift; if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; shift = TPS6507X_MAX_REG_ID - rid; data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1); if (data < 0) return data; else return (data & 1<<shift) ? 1 : 0; } static int tps6507x_pmic_enable(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int rid = rdev_get_id(dev); u8 shift; if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; shift = TPS6507X_MAX_REG_ID - rid; return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); } static int tps6507x_pmic_disable(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int rid = rdev_get_id(dev); u8 shift; if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2) return -EINVAL; shift = TPS6507X_MAX_REG_ID - rid; return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift); } static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, rid = rdev_get_id(dev); u8 reg, mask; switch (rid) { case TPS6507X_DCDC_1: reg = TPS6507X_REG_DEFDCDC1; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_2: if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC2_HIGH; else reg = TPS6507X_REG_DEFDCDC2_LOW; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_3: if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC3_HIGH; else reg = TPS6507X_REG_DEFDCDC3_LOW; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_LDO_1: reg = TPS6507X_REG_LDO_CTRL1; mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; break; case TPS6507X_LDO_2: reg = TPS6507X_REG_DEFLDO2; mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; break; default: return -EINVAL; } data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; data &= mask; return data; } static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev, unsigned selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, rid = rdev_get_id(dev); u8 reg, mask; switch (rid) { case TPS6507X_DCDC_1: reg = TPS6507X_REG_DEFDCDC1; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_2: if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC2_HIGH; else reg = TPS6507X_REG_DEFDCDC2_LOW; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_DCDC_3: if (tps->info[rid]->defdcdc_default) reg = TPS6507X_REG_DEFDCDC3_HIGH; else reg = TPS6507X_REG_DEFDCDC3_LOW; mask = TPS6507X_DEFDCDCX_DCDC_MASK; break; case TPS6507X_LDO_1: reg = TPS6507X_REG_LDO_CTRL1; mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK; break; case TPS6507X_LDO_2: reg = TPS6507X_REG_DEFLDO2; mask = TPS6507X_REG_DEFLDO2_LDO2_MASK; break; default: return -EINVAL; } data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; data &= ~mask; data |= selector; return tps6507x_pmic_reg_write(tps, reg, data); } static struct regulator_ops tps6507x_pmic_ops = { .is_enabled = tps6507x_pmic_is_enabled, .enable = tps6507x_pmic_enable, .disable = tps6507x_pmic_disable, .get_voltage_sel = tps6507x_pmic_get_voltage_sel, .set_voltage_sel = tps6507x_pmic_set_voltage_sel, .list_voltage = regulator_list_voltage_table, }; static int tps6507x_pmic_probe(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent); struct tps_info *info = &tps6507x_pmic_regs[0]; struct regulator_config config = { }; struct regulator_init_data *init_data; struct regulator_dev *rdev; struct tps6507x_pmic *tps; struct tps6507x_board *tps_board; int i; int error; /** * tps_board points to pmic related constants * coming from the board-evm file. */ tps_board = dev_get_platdata(tps6507x_dev->dev); if (!tps_board) return -EINVAL; /** * init_data points to array of regulator_init structures * coming from the board-evm file. */ init_data = tps_board->tps6507x_pmic_init_data; if (!init_data) return -EINVAL; tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; mutex_init(&tps->io_lock); /* common for all regulators */ tps->mfd = tps6507x_dev; for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) { /* Register the regulators */ tps->info[i] = info; if (init_data->driver_data) { struct tps6507x_reg_platform_data *data = init_data->driver_data; tps->info[i]->defdcdc_default = data->defdcdc_default; } tps->desc[i].name = info->name; tps->desc[i].id = i; tps->desc[i].n_voltages = info->table_len; tps->desc[i].volt_table = info->table; tps->desc[i].ops = &tps6507x_pmic_ops; tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].owner = THIS_MODULE; config.dev = tps6507x_dev->dev; config.init_data = init_data; config.driver_data = tps; rdev = regulator_register(&tps->desc[i], &config); if (IS_ERR(rdev)) { dev_err(tps6507x_dev->dev, "failed to register %s regulator\n", pdev->name); error = PTR_ERR(rdev); goto fail; } /* Save regulator for cleanup */ tps->rdev[i] = rdev; } tps6507x_dev->pmic = tps; platform_set_drvdata(pdev, tps6507x_dev); return 0; fail: while (--i >= 0) regulator_unregister(tps->rdev[i]); return error; } static int tps6507x_pmic_remove(struct platform_device *pdev) { struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev); struct tps6507x_pmic *tps = tps6507x_dev->pmic; int i; for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) regulator_unregister(tps->rdev[i]); return 0; } static struct platform_driver tps6507x_pmic_driver = { .driver = { .name = "tps6507x-pmic", .owner = THIS_MODULE, }, .probe = tps6507x_pmic_probe, .remove = tps6507x_pmic_remove, }; static int __init tps6507x_pmic_init(void) { return platform_driver_register(&tps6507x_pmic_driver); } subsys_initcall(tps6507x_pmic_init); static void __exit tps6507x_pmic_cleanup(void) { platform_driver_unregister(&tps6507x_pmic_driver); } module_exit(tps6507x_pmic_cleanup); MODULE_AUTHOR("Texas Instruments"); MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:tps6507x-pmic");