Skip to content

Commit 6900433

Browse files
committed
Merge tag 'for-linus-5.7-1' of git://github.com/cminyard/linux-ipmi
Pull IPMI updates from Corey Minyard: "Bug fixes for main IPMI driver, kcs updates A couple of bug fixes for the main IPMI driver, one functional and two annotations. The kcs driver has some significant updates that have been pending for a while, but I forgot to include in next until a week ago. But this code is only used by the people who are sending it to me, really, so it's not a big deal. I did want it to sit in next for at least a week, and it did result in a fix" * tag 'for-linus-5.7-1' of git://github.com/cminyard/linux-ipmi: ipmi: kcs: Fix aspeed_kcs_probe_of_v1() ipmi: Add missing annotation for ipmi_ssif_lock_cond() and ipmi_ssif_unlock_cond() ipmi: kcs: aspeed: Implement v2 bindings ipmi: kcs: Finish configuring ASPEED KCS device before enable dt-bindings: ipmi: aspeed: Introduce a v2 binding for KCS ipmi: fix hung processes in __get_guid() drivers: char: ipmi: ipmi_msghandler: Pass lockdep expression to RCU lists
2 parents 21c5b3c + e963876 commit 6900433

File tree

4 files changed

+153
-38
lines changed

4 files changed

+153
-38
lines changed
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
* Aspeed KCS (Keyboard Controller Style) IPMI interface
1+
# Aspeed KCS (Keyboard Controller Style) IPMI interface
22

33
The Aspeed SOCs (AST2400 and AST2500) are commonly used as BMCs
44
(Baseboard Management Controllers) and the KCS interface can be
55
used to perform in-band IPMI communication with their host.
66

7+
## v1
78
Required properties:
89
- compatible : should be one of
910
"aspeed,ast2400-kcs-bmc"
@@ -12,14 +13,21 @@ Required properties:
1213
- kcs_chan : The LPC channel number in the controller
1314
- kcs_addr : The host CPU IO map address
1415

16+
## v2
17+
Required properties:
18+
- compatible : should be one of
19+
"aspeed,ast2400-kcs-bmc-v2"
20+
"aspeed,ast2500-kcs-bmc-v2"
21+
- reg : The address and size of the IDR, ODR and STR registers
22+
- interrupts : interrupt generated by the controller
23+
- aspeed,lpc-io-reg : The host CPU LPC IO address for the device
1524

1625
Example:
1726

18-
kcs3: kcs3@0 {
19-
compatible = "aspeed,ast2500-kcs-bmc";
20-
reg = <0x0 0x80>;
27+
kcs3: kcs@24 {
28+
compatible = "aspeed,ast2500-kcs-bmc-v2";
29+
reg = <0x24 0x1>, <0x30 0x1>, <0x3c 0x1>;
30+
aspeed,lpc-reg = <0xca2>;
2131
interrupts = <8>;
22-
kcs_chan = <3>;
23-
kcs_addr = <0xCA2>;
2432
status = "okay";
2533
};

drivers/char/ipmi/ipmi_msghandler.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ static DEFINE_MUTEX(ipmidriver_mutex);
618618

619619
static LIST_HEAD(ipmi_interfaces);
620620
static DEFINE_MUTEX(ipmi_interfaces_mutex);
621+
#define ipmi_interfaces_mutex_held() \
622+
lockdep_is_held(&ipmi_interfaces_mutex)
621623
static struct srcu_struct ipmi_interfaces_srcu;
622624

623625
/*
@@ -1321,7 +1323,8 @@ static void _ipmi_destroy_user(struct ipmi_user *user)
13211323
* synchronize_srcu()) then free everything in that list.
13221324
*/
13231325
mutex_lock(&intf->cmd_rcvrs_mutex);
1324-
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1326+
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
1327+
lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
13251328
if (rcvr->user == user) {
13261329
list_del_rcu(&rcvr->link);
13271330
rcvr->next = rcvrs;
@@ -1599,7 +1602,8 @@ static struct cmd_rcvr *find_cmd_rcvr(struct ipmi_smi *intf,
15991602
{
16001603
struct cmd_rcvr *rcvr;
16011604

1602-
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1605+
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
1606+
lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
16031607
if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
16041608
&& (rcvr->chans & (1 << chan)))
16051609
return rcvr;
@@ -1614,7 +1618,8 @@ static int is_cmd_rcvr_exclusive(struct ipmi_smi *intf,
16141618
{
16151619
struct cmd_rcvr *rcvr;
16161620

1617-
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
1621+
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link,
1622+
lockdep_is_held(&intf->cmd_rcvrs_mutex)) {
16181623
if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
16191624
&& (rcvr->chans & chans))
16201625
return 0;
@@ -3188,8 +3193,8 @@ static void __get_guid(struct ipmi_smi *intf)
31883193
if (rv)
31893194
/* Send failed, no GUID available. */
31903195
bmc->dyn_guid_set = 0;
3191-
3192-
wait_event(intf->waitq, bmc->dyn_guid_set != 2);
3196+
else
3197+
wait_event(intf->waitq, bmc->dyn_guid_set != 2);
31933198

31943199
/* dyn_guid_set makes the guid data available. */
31953200
smp_rmb();
@@ -3450,7 +3455,8 @@ int ipmi_add_smi(struct module *owner,
34503455
/* Look for a hole in the numbers. */
34513456
i = 0;
34523457
link = &ipmi_interfaces;
3453-
list_for_each_entry_rcu(tintf, &ipmi_interfaces, link) {
3458+
list_for_each_entry_rcu(tintf, &ipmi_interfaces, link,
3459+
ipmi_interfaces_mutex_held()) {
34543460
if (tintf->intf_num != i) {
34553461
link = &tintf->link;
34563462
break;

drivers/char/ipmi/ipmi_ssif.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,15 @@ static int start_send(struct ssif_info *ssif_info,
313313

314314
static unsigned long *ipmi_ssif_lock_cond(struct ssif_info *ssif_info,
315315
unsigned long *flags)
316+
__acquires(&ssif_info->lock)
316317
{
317318
spin_lock_irqsave(&ssif_info->lock, *flags);
318319
return flags;
319320
}
320321

321322
static void ipmi_ssif_unlock_cond(struct ssif_info *ssif_info,
322323
unsigned long *flags)
324+
__releases(&ssif_info->lock)
323325
{
324326
spin_unlock_irqrestore(&ssif_info->lock, *flags);
325327
}

drivers/char/ipmi/kcs_bmc_aspeed.c

Lines changed: 125 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/mfd/syscon.h>
1313
#include <linux/module.h>
1414
#include <linux/of.h>
15+
#include <linux/of_address.h>
1516
#include <linux/platform_device.h>
1617
#include <linux/poll.h>
1718
#include <linux/regmap.h>
@@ -233,58 +234,154 @@ static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
233234
{ .idr = LPC_IDR4, .odr = LPC_ODR4, .str = LPC_STR4 },
234235
};
235236

236-
static int aspeed_kcs_probe(struct platform_device *pdev)
237+
static struct kcs_bmc *aspeed_kcs_probe_of_v1(struct platform_device *pdev)
237238
{
238-
struct device *dev = &pdev->dev;
239239
struct aspeed_kcs_bmc *priv;
240-
struct kcs_bmc *kcs_bmc;
241-
u32 chan, addr;
240+
struct device_node *np;
241+
struct kcs_bmc *kcs;
242+
u32 channel;
243+
u32 slave;
242244
int rc;
243245

244-
rc = of_property_read_u32(dev->of_node, "kcs_chan", &chan);
245-
if ((rc != 0) || (chan == 0 || chan > KCS_CHANNEL_MAX)) {
246-
dev_err(dev, "no valid 'kcs_chan' configured\n");
247-
return -ENODEV;
246+
np = pdev->dev.of_node;
247+
248+
rc = of_property_read_u32(np, "kcs_chan", &channel);
249+
if ((rc != 0) || (channel == 0 || channel > KCS_CHANNEL_MAX)) {
250+
dev_err(&pdev->dev, "no valid 'kcs_chan' configured\n");
251+
return ERR_PTR(-EINVAL);
252+
}
253+
254+
kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
255+
if (!kcs)
256+
return ERR_PTR(-ENOMEM);
257+
258+
priv = kcs_bmc_priv(kcs);
259+
priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
260+
if (IS_ERR(priv->map)) {
261+
dev_err(&pdev->dev, "Couldn't get regmap\n");
262+
return ERR_PTR(-ENODEV);
248263
}
249264

250-
rc = of_property_read_u32(dev->of_node, "kcs_addr", &addr);
265+
rc = of_property_read_u32(np, "kcs_addr", &slave);
251266
if (rc) {
252-
dev_err(dev, "no valid 'kcs_addr' configured\n");
253-
return -ENODEV;
267+
dev_err(&pdev->dev, "no valid 'kcs_addr' configured\n");
268+
return ERR_PTR(-EINVAL);
269+
}
270+
271+
kcs->ioreg = ast_kcs_bmc_ioregs[channel - 1];
272+
aspeed_kcs_set_address(kcs, slave);
273+
274+
return kcs;
275+
}
276+
277+
static int aspeed_kcs_calculate_channel(const struct kcs_ioreg *regs)
278+
{
279+
int i;
280+
281+
for (i = 0; i < ARRAY_SIZE(ast_kcs_bmc_ioregs); i++) {
282+
if (!memcmp(&ast_kcs_bmc_ioregs[i], regs, sizeof(*regs)))
283+
return i + 1;
254284
}
255285

256-
kcs_bmc = kcs_bmc_alloc(dev, sizeof(*priv), chan);
257-
if (!kcs_bmc)
258-
return -ENOMEM;
286+
return -EINVAL;
287+
}
288+
289+
static struct kcs_bmc *aspeed_kcs_probe_of_v2(struct platform_device *pdev)
290+
{
291+
struct aspeed_kcs_bmc *priv;
292+
struct device_node *np;
293+
struct kcs_ioreg ioreg;
294+
struct kcs_bmc *kcs;
295+
const __be32 *reg;
296+
int channel;
297+
u32 slave;
298+
int rc;
299+
300+
np = pdev->dev.of_node;
301+
302+
/* Don't translate addresses, we want offsets for the regmaps */
303+
reg = of_get_address(np, 0, NULL, NULL);
304+
if (!reg)
305+
return ERR_PTR(-EINVAL);
306+
ioreg.idr = be32_to_cpup(reg);
307+
308+
reg = of_get_address(np, 1, NULL, NULL);
309+
if (!reg)
310+
return ERR_PTR(-EINVAL);
311+
ioreg.odr = be32_to_cpup(reg);
312+
313+
reg = of_get_address(np, 2, NULL, NULL);
314+
if (!reg)
315+
return ERR_PTR(-EINVAL);
316+
ioreg.str = be32_to_cpup(reg);
259317

260-
priv = kcs_bmc_priv(kcs_bmc);
261-
priv->map = syscon_node_to_regmap(dev->parent->of_node);
318+
channel = aspeed_kcs_calculate_channel(&ioreg);
319+
if (channel < 0)
320+
return ERR_PTR(channel);
321+
322+
kcs = kcs_bmc_alloc(&pdev->dev, sizeof(struct aspeed_kcs_bmc), channel);
323+
if (!kcs)
324+
return ERR_PTR(-ENOMEM);
325+
326+
kcs->ioreg = ioreg;
327+
328+
priv = kcs_bmc_priv(kcs);
329+
priv->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
262330
if (IS_ERR(priv->map)) {
263-
dev_err(dev, "Couldn't get regmap\n");
264-
return -ENODEV;
331+
dev_err(&pdev->dev, "Couldn't get regmap\n");
332+
return ERR_PTR(-ENODEV);
265333
}
266334

267-
kcs_bmc->ioreg = ast_kcs_bmc_ioregs[chan - 1];
335+
rc = of_property_read_u32(np, "aspeed,lpc-io-reg", &slave);
336+
if (rc)
337+
return ERR_PTR(rc);
338+
339+
aspeed_kcs_set_address(kcs, slave);
340+
341+
return kcs;
342+
}
343+
344+
static int aspeed_kcs_probe(struct platform_device *pdev)
345+
{
346+
struct device *dev = &pdev->dev;
347+
struct kcs_bmc *kcs_bmc;
348+
struct device_node *np;
349+
int rc;
350+
351+
np = pdev->dev.of_node;
352+
if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc") ||
353+
of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc"))
354+
kcs_bmc = aspeed_kcs_probe_of_v1(pdev);
355+
else if (of_device_is_compatible(np, "aspeed,ast2400-kcs-bmc-v2") ||
356+
of_device_is_compatible(np, "aspeed,ast2500-kcs-bmc-v2"))
357+
kcs_bmc = aspeed_kcs_probe_of_v2(pdev);
358+
else
359+
return -EINVAL;
360+
361+
if (IS_ERR(kcs_bmc))
362+
return PTR_ERR(kcs_bmc);
363+
268364
kcs_bmc->io_inputb = aspeed_kcs_inb;
269365
kcs_bmc->io_outputb = aspeed_kcs_outb;
270366

271-
dev_set_drvdata(dev, kcs_bmc);
272-
273-
aspeed_kcs_set_address(kcs_bmc, addr);
274-
aspeed_kcs_enable_channel(kcs_bmc, true);
275367
rc = aspeed_kcs_config_irq(kcs_bmc, pdev);
276368
if (rc)
277369
return rc;
278370

371+
dev_set_drvdata(dev, kcs_bmc);
372+
373+
aspeed_kcs_enable_channel(kcs_bmc, true);
374+
279375
rc = misc_register(&kcs_bmc->miscdev);
280376
if (rc) {
281377
dev_err(dev, "Unable to register device\n");
282378
return rc;
283379
}
284380

285-
pr_info("channel=%u addr=0x%x idr=0x%x odr=0x%x str=0x%x\n",
286-
chan, addr,
287-
kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr, kcs_bmc->ioreg.str);
381+
dev_dbg(&pdev->dev,
382+
"Probed KCS device %d (IDR=0x%x, ODR=0x%x, STR=0x%x)\n",
383+
kcs_bmc->channel, kcs_bmc->ioreg.idr, kcs_bmc->ioreg.odr,
384+
kcs_bmc->ioreg.str);
288385

289386
return 0;
290387
}
@@ -301,6 +398,8 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
301398
static const struct of_device_id ast_kcs_bmc_match[] = {
302399
{ .compatible = "aspeed,ast2400-kcs-bmc" },
303400
{ .compatible = "aspeed,ast2500-kcs-bmc" },
401+
{ .compatible = "aspeed,ast2400-kcs-bmc-v2" },
402+
{ .compatible = "aspeed,ast2500-kcs-bmc-v2" },
304403
{ }
305404
};
306405
MODULE_DEVICE_TABLE(of, ast_kcs_bmc_match);

0 commit comments

Comments
 (0)