From: Cyril Bur <cyrilbur@gmail.com>
To: "Cédric Le Goater" <clg@kaod.org>, openbmc@lists.ozlabs.org
Subject: Re: [PATCH linux dev-4.7 7/8] ipmi: maintain a request expiry list
Date: Thu, 03 Nov 2016 11:26:09 +1100 [thread overview]
Message-ID: <1478132769.728.3.camel@gmail.com> (raw)
In-Reply-To: <1477465067-19034-8-git-send-email-clg@kaod.org>
On Wed, 2016-10-26 at 08:57 +0200, Cédric Le Goater wrote:
> Regarding the response expiration handling, the IPMI spec says :
>
> The BMC must not return a given response once the corresponding
> Request-to-Response interval has passed. The BMC can ensure this
> by maintaining its own internal list of outstanding requests
> through
> the interface. The BMC could age and expire the entries in the
> list
> by expiring the entries at an interval that is somewhat shorter
> than
> the specified Request-to-Response interval....
>
> To handle such case, we maintain list of received requests using the
> seq number of the BT message to identify them. The list is updated
> each time a request is received and a response is sent. The
> expiration
> of the reponses is handled at each updates but also with a timer.
>
I agree that the BMC kernel is most logical place to do this, at the
moment btbridged does attempt something similar no?
Should we patch btbridged to not? Should I least remove duplicated
logic?
> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> ---
> drivers/char/ipmi/bt-bmc.c | 132
> +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 132 insertions(+)
>
> diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
> index b49e61320952..228ecdb689de 100644
> --- a/drivers/char/ipmi/bt-bmc.c
> +++ b/drivers/char/ipmi/bt-bmc.c
> @@ -17,6 +17,7 @@
> #include <linux/platform_device.h>
> #include <linux/poll.h>
> #include <linux/sched.h>
> +#include <linux/slab.h>
> #include <linux/timer.h>
>
> /*
> @@ -57,6 +58,15 @@
>
> #define BT_BMC_BUFFER_SIZE 256
>
> +#define BT_BMC_RESPONSE_TIME 5 /* seconds */
> +
> +struct ipmi_request {
> + struct list_head list;
> +
> + u8 seq;
> + unsigned long expires;
> +};
> +
> struct bt_bmc {
> struct device dev;
> struct miscdevice miscdev;
> @@ -65,6 +75,11 @@ struct bt_bmc {
> wait_queue_head_t queue;
> struct timer_list poll_timer;
> struct mutex mutex;
> +
> + unsigned int response_time;
> + struct timer_list requests_timer;
> + spinlock_t requests_lock;
> + struct list_head requests;
> };
>
> static atomic_t open_count = ATOMIC_INIT(0);
> @@ -163,6 +178,94 @@ static int bt_bmc_open(struct inode *inode,
> struct file *file)
> }
>
> /*
> + * lock should be held
> + */
> +static void drop_expired_requests(struct bt_bmc *bt_bmc)
> +{
> + unsigned long flags = 0;
> + struct ipmi_request *req, *next;
> + unsigned long next_expires = 0;
> + int start_timer = 0;
> +
> + spin_lock_irqsave(&bt_bmc->requests_lock, flags);
> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list)
> {
> + if (time_after_eq(jiffies, req->expires)) {
> + pr_warn("BT: request seq:%d has expired.
> dropping\n",
> + req->seq);
> + list_del(&req->list);
> + kfree(req);
> + continue;
> + }
> + if (!start_timer) {
> + start_timer = 1;
> + next_expires = req->expires;
> + } else {
> + next_expires = min(next_expires, req-
> >expires);
> + }
> + }
> + spin_unlock_irqrestore(&bt_bmc->requests_lock, flags);
> +
> + /* and possibly restart */
> + if (start_timer)
> + mod_timer(&bt_bmc->requests_timer, next_expires);
> +}
> +
> +static void requests_timer(unsigned long data)
> +{
> + struct bt_bmc *bt_bmc = (void *)data;
> +
> + drop_expired_requests(bt_bmc);
> +}
> +
> +static int bt_bmc_add_request(struct bt_bmc *bt_bmc, u8 seq)
> +{
> + struct ipmi_request *req;
> +
> + req = kmalloc(sizeof(*req), GFP_KERNEL);
> + if (!req)
> + return -ENOMEM;
> +
> + req->seq = seq;
> + req->expires = jiffies +
> + msecs_to_jiffies(bt_bmc->response_time * 1000);
> +
> + spin_lock(&bt_bmc->requests_lock);
> + list_add(&req->list, &bt_bmc->requests);
> + spin_unlock(&bt_bmc->requests_lock);
> +
> + drop_expired_requests(bt_bmc);
> + return 0;
> +}
> +
> +static int bt_bmc_remove_request(struct bt_bmc *bt_bmc, u8 seq)
> +{
> + struct ipmi_request *req, *next;
> + int ret = -EBADRQC; /* Invalid request code */
> +
> + spin_lock(&bt_bmc->requests_lock);
> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list)
> {
> + /*
> + * The sequence number should be unique, so remove
> the
> + * first matching request found. If there are
> others,
> + * they should expire
> + */
> + if (req->seq == seq) {
> + list_del(&req->list);
> + kfree(req);
> + ret = 0;
> + break;
> + }
> + }
> + spin_unlock(&bt_bmc->requests_lock);
> +
> + if (ret)
> + pr_warn("BT: request seq:%d is invalid\n", seq);
> +
> + drop_expired_requests(bt_bmc);
> + return ret;
> +}
> +
> +/*
> * The BT (Block Transfer) interface means that entire messages are
> * buffered by the host before a notification is sent to the BMC
> that
> * there is data to be read. The first byte is the length and the
> @@ -231,6 +334,13 @@ static ssize_t bt_bmc_read(struct file *file,
> char __user *buf,
> len_byte = 0;
> }
>
> + if (ret > 0) {
> + int ret2 = bt_bmc_add_request(bt_bmc, kbuffer[2]);
> +
> + if (ret2)
> + ret = ret2;
> + }
> +
> clr_b_busy(bt_bmc);
>
> out_unlock:
> @@ -283,12 +393,20 @@ static ssize_t bt_bmc_write(struct file *file,
> const char __user *buf,
> clr_wr_ptr(bt_bmc);
>
> while (count) {
> + int ret2;
> +
> nwritten = min_t(ssize_t, count, sizeof(kbuffer));
> if (copy_from_user(&kbuffer, buf, nwritten)) {
> ret = -EFAULT;
> break;
> }
>
> + ret2 = bt_bmc_remove_request(bt_bmc, kbuffer[2]);
> + if (ret2) {
> + ret = ret2;
> + break;
> + }
> +
> bt_writen(bt_bmc, kbuffer, nwritten);
>
> count -= nwritten;
> @@ -438,6 +556,8 @@ static int bt_bmc_probe(struct platform_device
> *pdev)
>
> mutex_init(&bt_bmc->mutex);
> init_waitqueue_head(&bt_bmc->queue);
> + INIT_LIST_HEAD(&bt_bmc->requests);
> + spin_lock_init(&bt_bmc->requests_lock);
>
> bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
> bt_bmc->miscdev.name = DEVICE_NAME,
> @@ -451,6 +571,8 @@ static int bt_bmc_probe(struct platform_device
> *pdev)
>
> bt_bmc_config_irq(bt_bmc, pdev);
>
> + bt_bmc->response_time = BT_BMC_RESPONSE_TIME;
> +
> if (bt_bmc->irq) {
> dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
> } else {
> @@ -468,6 +590,9 @@ static int bt_bmc_probe(struct platform_device
> *pdev)
> BT_CR0_ENABLE_IBT,
> bt_bmc->base + BT_CR0);
>
> + setup_timer(&bt_bmc->requests_timer, requests_timer,
> + (unsigned long)bt_bmc);
> +
> clr_b_busy(bt_bmc);
>
> return 0;
> @@ -476,10 +601,17 @@ static int bt_bmc_probe(struct platform_device
> *pdev)
> static int bt_bmc_remove(struct platform_device *pdev)
> {
> struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
> + struct ipmi_request *req, *next;
>
> misc_deregister(&bt_bmc->miscdev);
> if (!bt_bmc->irq)
> del_timer_sync(&bt_bmc->poll_timer);
> +
> + del_timer_sync(&bt_bmc->requests_timer);
> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list)
> {
> + list_del(&req->list);
> + kfree(req);
> + }
> return 0;
> }
>
next prev parent reply other threads:[~2016-11-03 0:26 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-26 6:57 [PATCH linux dev-4.7 0/8] BT driver sync up Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 1/8] Revert "misc: Add Aspeed BT IPMI host driver" Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 2/8] ARM: aspeed: remove previous definitions in default config Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 3/8] ARM: dts: aspeed: remove previous iBT definitions Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 4/8] ipmi: add an Aspeed BT IPMI BMC driver Cédric Le Goater
2016-11-02 0:00 ` Joel Stanley
2016-11-02 7:08 ` Cédric Le Goater
2016-11-03 0:56 ` Cyril Bur
2016-11-03 2:46 ` Joel Stanley
2016-11-03 2:48 ` Cyril Bur
2016-10-26 6:57 ` [PATCH linux dev-4.7 5/8] ARM: aspeed: Add defconfigs for CONFIG_ASPEED_BT_IPMI_BMC Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 6/8] ARM: dts: aspeed: Enable BT IPMI BMC device Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 7/8] ipmi: maintain a request expiry list Cédric Le Goater
2016-11-03 0:26 ` Cyril Bur [this message]
2016-11-03 9:06 ` Cédric Le Goater
2016-11-10 7:53 ` Cédric Le Goater
2016-11-03 18:23 ` Patrick Williams
2016-11-03 18:46 ` Cédric Le Goater
2016-11-04 1:55 ` Patrick Williams
2016-11-04 8:09 ` Cédric Le Goater
2016-11-04 18:22 ` Brendan Higgins
2016-11-07 5:25 ` Cédric Le Goater
2016-11-07 15:02 ` Patrick Williams
2016-11-07 19:29 ` Brendan Higgins
2016-11-08 9:58 ` Cédric Le Goater
2016-10-26 6:57 ` [PATCH linux dev-4.7 8/8] ipmi: add a sysfs file for configure maximum response time Cédric Le Goater
2016-11-03 0:30 ` [PATCH linux dev-4.7 0/8] BT driver sync up Cyril Bur
2016-11-10 9:13 ` Cédric Le Goater
2016-11-10 11:33 ` Joel Stanley
2016-11-10 12:04 ` Cédric Le Goater
2016-11-10 12:11 ` Joel Stanley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1478132769.728.3.camel@gmail.com \
--to=cyrilbur@gmail.com \
--cc=clg@kaod.org \
--cc=openbmc@lists.ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.