From: Oliver Neukum <oneukum@suse.de>
To: Pavel Machek <pavel@ucw.cz>
Cc: pali.rohar@gmail.com, sre@debian.org, sre@ring0.de,
kernel list <linux-kernel@vger.kernel.org>,
linux-arm-kernel <linux-arm-kernel@lists.infradead.org>,
linux-omap@vger.kernel.org, tony@atomide.com, khilman@kernel.org,
aaro.koskinen@iki.fi, ivo.g.dimitrov.75@gmail.com,
linux-bluetooth@vger.kernel.org, marcel@holtmann.org
Subject: Re: bluetooth: Add hci_h4p driver
Date: Mon, 15 Dec 2014 11:01:50 +0100 [thread overview]
Message-ID: <1418637710.4443.11.camel@linux-0dmf.site> (raw)
In-Reply-To: <20141213223727.GA13894@amd>
Hi,
a few remarks about possible issues.
Regards
Oliver
> +static int h4p_send_negotiation(struct h4p_info *info)
> +{
> + struct h4p_neg_cmd *neg_cmd;
> + struct h4p_neg_hdr *neg_hdr;
> + struct sk_buff *skb;
> + int err, len;
> + u16 sysclk = 38400;
> +
> + printk("Sending negotiation..");
> + len = sizeof(*neg_cmd) + sizeof(*neg_hdr) + H4_TYPE_SIZE;
> +
> + skb = bt_skb_alloc(len, GFP_KERNEL);
> + if (!skb)
> + return -ENOMEM;
> +
> + memset(skb->data, 0x00, len);
> + *skb_put(skb, 1) = H4_NEG_PKT;
> + neg_hdr = (struct h4p_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
> + neg_cmd = (struct h4p_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
> +
> + neg_hdr->dlen = sizeof(*neg_cmd);
> + neg_cmd->ack = H4P_NEG_REQ;
> + neg_cmd->baud = cpu_to_le16(BT_BAUDRATE_DIVIDER/MAX_BAUD_RATE);
> + neg_cmd->proto = H4P_PROTO_BYTE;
> + neg_cmd->sys_clk = cpu_to_le16(sysclk);
> +
> + h4p_change_speed(info, INIT_SPEED);
> +
> + h4p_set_rts(info, 1);
> + info->init_error = 0;
> + init_completion(&info->init_completion);
> +
> + h4p_simple_send_frame(info, skb);
> +
> + if (!wait_for_completion_interruptible_timeout(&info->init_completion,
> + msecs_to_jiffies(1000))) {
> + printk("h4p: negotiation did not return\n");
Memory leak in the error case
> + return -ETIMEDOUT;
> + }
> +
> + if (info->init_error < 0)
> + return info->init_error;
> +
> + /* Change to operational settings */
> + h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
> + h4p_set_rts(info, 0);
> + h4p_change_speed(info, MAX_BAUD_RATE);
> +
> + err = h4p_wait_for_cts(info, 1, 100);
> + if (err < 0)
> + return err;
> +
> + h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
> + init_completion(&info->init_completion);
> + err = h4p_send_alive_packet(info);
> +
> + if (err < 0)
> + return err;
> +
> + if (!wait_for_completion_interruptible_timeout(&info->init_completion,
> + msecs_to_jiffies(1000)))
> + return -ETIMEDOUT;
> +
> + if (info->init_error < 0)
> + return info->init_error;
> +
> + printk("Negotiation successful\n");
> + return 0;
> +}
> +static unsigned int h4p_get_data_len(struct h4p_info *info,
> + struct sk_buff *skb)
> +{
> + long retval = -1;
> + struct hci_acl_hdr *acl_hdr;
> + struct hci_sco_hdr *sco_hdr;
> + struct hci_event_hdr *evt_hdr;
> + struct h4p_neg_hdr *neg_hdr;
> + struct h4p_alive_hdr *alive_hdr;
> + struct h4p_radio_hdr *radio_hdr;
> +
> + switch (bt_cb(skb)->pkt_type) {
> + case H4_EVT_PKT:
> + evt_hdr = (struct hci_event_hdr *)skb->data;
> + retval = evt_hdr->plen;
> + break;
> + case H4_ACL_PKT:
> + acl_hdr = (struct hci_acl_hdr *)skb->data;
> + retval = le16_to_cpu(acl_hdr->dlen);
Could you explain, why only this needs endianness converted?
> + break;
> + case H4_SCO_PKT:
> + sco_hdr = (struct hci_sco_hdr *)skb->data;
> + retval = sco_hdr->dlen;
> + break;
> + case H4_RADIO_PKT:
> + radio_hdr = (struct h4p_radio_hdr *)skb->data;
> + retval = radio_hdr->dlen;
> + break;
> + case H4_NEG_PKT:
> + neg_hdr = (struct h4p_neg_hdr *)skb->data;
> + retval = neg_hdr->dlen;
> + break;
> + case H4_ALIVE_PKT:
> + alive_hdr = (struct h4p_alive_hdr *)skb->data;
> + retval = alive_hdr->dlen;
> + break;
> + }
> +
> + return retval;
> +}
> +static void h4p_rx_tasklet(unsigned long data)
> +{
> + u8 byte;
> + struct h4p_info *info = (struct h4p_info *)data;
> +
> + BT_DBG("tasklet woke up");
> + BT_DBG("rx_tasklet woke up");
Isn't this a bit redundant?
> +
> + while (h4p_inb(info, UART_LSR) & UART_LSR_DR) {
> + byte = h4p_inb(info, UART_RX);
> + BT_DBG("[in: %02x]", byte);
> + if (info->garbage_bytes) {
> + info->garbage_bytes--;
> + continue;
> + }
> + if (info->rx_skb == NULL) {
> + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
> + GFP_ATOMIC | GFP_DMA);
> + if (!info->rx_skb) {
> + dev_err(info->dev,
> + "No memory for new packet\n");
> + goto finish_rx;
> + }
> + info->rx_state = WAIT_FOR_PKT_TYPE;
> + info->rx_skb->dev = (void *)info->hdev;
> + }
> + info->hdev->stat.byte_rx++;
> + h4p_handle_byte(info, byte);
> + }
> +
> + if (!info->rx_enabled) {
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
> + info->autorts) {
> + __h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS);
> + info->autorts = 0;
> + }
> + /* Flush posted write to avoid spurious interrupts */
> + h4p_inb(info, UART_OMAP_SCR);
> + h4p_set_clk(info, &info->rx_clocks_en, 0);
> + }
> +
> +finish_rx:
> + BT_DBG("rx_ended");
> +}
> +
> +static void h4p_tx_tasklet(unsigned long data)
> +{
> + unsigned int sent = 0;
> + struct sk_buff *skb;
> + struct h4p_info *info = (struct h4p_info *)data;
> +
> + BT_DBG("tasklet woke up");
> + BT_DBG("tx_tasklet woke up");
Doubled?
> + if (info->autorts != info->rx_enabled) {
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
> + if (info->autorts && !info->rx_enabled) {
> + __h4p_set_auto_ctsrts(info, 0,
> + UART_EFR_RTS);
> + info->autorts = 0;
> + }
> + if (!info->autorts && info->rx_enabled) {
> + __h4p_set_auto_ctsrts(info, 1,
> + UART_EFR_RTS);
> + info->autorts = 1;
> + }
> + } else {
> + h4p_outb(info, UART_OMAP_SCR,
> + h4p_inb(info, UART_OMAP_SCR) |
> + UART_OMAP_SCR_EMPTY_THR);
> + goto finish_tx;
> + }
> + }
> +
> + skb = skb_dequeue(&info->txq);
> + if (!skb) {
> + /* No data in buffer */
> + BT_DBG("skb ready");
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
> + h4p_outb(info, UART_IER,
> + h4p_inb(info, UART_IER) &
> + ~UART_IER_THRI);
> + h4p_inb(info, UART_OMAP_SCR);
> + h4p_disable_tx(info);
> + return;
> + }
> + h4p_outb(info, UART_OMAP_SCR,
> + h4p_inb(info, UART_OMAP_SCR) |
> + UART_OMAP_SCR_EMPTY_THR);
> + goto finish_tx;
> + }
> +
> + /* Copy data to tx fifo */
> + while (!(h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
> + (sent < skb->len)) {
> + //printk("[Out: %02x]", skb->data[sent]);
> + //printk("%02x ", skb->data[sent]);
> + h4p_outb(info, UART_TX, skb->data[sent]);
> + sent++;
> + }
> +
> + info->hdev->stat.byte_tx += sent;
> + if (skb->len == sent) {
> + kfree_skb(skb);
> + } else {
> + skb_pull(skb, sent);
> + skb_queue_head(&info->txq, skb);
> + }
> +
> + h4p_outb(info, UART_OMAP_SCR, h4p_inb(info, UART_OMAP_SCR) &
> + ~UART_OMAP_SCR_EMPTY_THR);
> + h4p_outb(info, UART_IER, h4p_inb(info, UART_IER) |
> + UART_IER_THRI);
> +
> +finish_tx:
> + /* Flush posted write to avoid spurious interrupts */
> + h4p_inb(info, UART_OMAP_SCR);
> +
> +}
WARNING: multiple messages have this Message-ID (diff)
From: oneukum@suse.de (Oliver Neukum)
To: linux-arm-kernel@lists.infradead.org
Subject: bluetooth: Add hci_h4p driver
Date: Mon, 15 Dec 2014 11:01:50 +0100 [thread overview]
Message-ID: <1418637710.4443.11.camel@linux-0dmf.site> (raw)
In-Reply-To: <20141213223727.GA13894@amd>
Hi,
a few remarks about possible issues.
Regards
Oliver
> +static int h4p_send_negotiation(struct h4p_info *info)
> +{
> + struct h4p_neg_cmd *neg_cmd;
> + struct h4p_neg_hdr *neg_hdr;
> + struct sk_buff *skb;
> + int err, len;
> + u16 sysclk = 38400;
> +
> + printk("Sending negotiation..");
> + len = sizeof(*neg_cmd) + sizeof(*neg_hdr) + H4_TYPE_SIZE;
> +
> + skb = bt_skb_alloc(len, GFP_KERNEL);
> + if (!skb)
> + return -ENOMEM;
> +
> + memset(skb->data, 0x00, len);
> + *skb_put(skb, 1) = H4_NEG_PKT;
> + neg_hdr = (struct h4p_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
> + neg_cmd = (struct h4p_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
> +
> + neg_hdr->dlen = sizeof(*neg_cmd);
> + neg_cmd->ack = H4P_NEG_REQ;
> + neg_cmd->baud = cpu_to_le16(BT_BAUDRATE_DIVIDER/MAX_BAUD_RATE);
> + neg_cmd->proto = H4P_PROTO_BYTE;
> + neg_cmd->sys_clk = cpu_to_le16(sysclk);
> +
> + h4p_change_speed(info, INIT_SPEED);
> +
> + h4p_set_rts(info, 1);
> + info->init_error = 0;
> + init_completion(&info->init_completion);
> +
> + h4p_simple_send_frame(info, skb);
> +
> + if (!wait_for_completion_interruptible_timeout(&info->init_completion,
> + msecs_to_jiffies(1000))) {
> + printk("h4p: negotiation did not return\n");
Memory leak in the error case
> + return -ETIMEDOUT;
> + }
> +
> + if (info->init_error < 0)
> + return info->init_error;
> +
> + /* Change to operational settings */
> + h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
> + h4p_set_rts(info, 0);
> + h4p_change_speed(info, MAX_BAUD_RATE);
> +
> + err = h4p_wait_for_cts(info, 1, 100);
> + if (err < 0)
> + return err;
> +
> + h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
> + init_completion(&info->init_completion);
> + err = h4p_send_alive_packet(info);
> +
> + if (err < 0)
> + return err;
> +
> + if (!wait_for_completion_interruptible_timeout(&info->init_completion,
> + msecs_to_jiffies(1000)))
> + return -ETIMEDOUT;
> +
> + if (info->init_error < 0)
> + return info->init_error;
> +
> + printk("Negotiation successful\n");
> + return 0;
> +}
> +static unsigned int h4p_get_data_len(struct h4p_info *info,
> + struct sk_buff *skb)
> +{
> + long retval = -1;
> + struct hci_acl_hdr *acl_hdr;
> + struct hci_sco_hdr *sco_hdr;
> + struct hci_event_hdr *evt_hdr;
> + struct h4p_neg_hdr *neg_hdr;
> + struct h4p_alive_hdr *alive_hdr;
> + struct h4p_radio_hdr *radio_hdr;
> +
> + switch (bt_cb(skb)->pkt_type) {
> + case H4_EVT_PKT:
> + evt_hdr = (struct hci_event_hdr *)skb->data;
> + retval = evt_hdr->plen;
> + break;
> + case H4_ACL_PKT:
> + acl_hdr = (struct hci_acl_hdr *)skb->data;
> + retval = le16_to_cpu(acl_hdr->dlen);
Could you explain, why only this needs endianness converted?
> + break;
> + case H4_SCO_PKT:
> + sco_hdr = (struct hci_sco_hdr *)skb->data;
> + retval = sco_hdr->dlen;
> + break;
> + case H4_RADIO_PKT:
> + radio_hdr = (struct h4p_radio_hdr *)skb->data;
> + retval = radio_hdr->dlen;
> + break;
> + case H4_NEG_PKT:
> + neg_hdr = (struct h4p_neg_hdr *)skb->data;
> + retval = neg_hdr->dlen;
> + break;
> + case H4_ALIVE_PKT:
> + alive_hdr = (struct h4p_alive_hdr *)skb->data;
> + retval = alive_hdr->dlen;
> + break;
> + }
> +
> + return retval;
> +}
> +static void h4p_rx_tasklet(unsigned long data)
> +{
> + u8 byte;
> + struct h4p_info *info = (struct h4p_info *)data;
> +
> + BT_DBG("tasklet woke up");
> + BT_DBG("rx_tasklet woke up");
Isn't this a bit redundant?
> +
> + while (h4p_inb(info, UART_LSR) & UART_LSR_DR) {
> + byte = h4p_inb(info, UART_RX);
> + BT_DBG("[in: %02x]", byte);
> + if (info->garbage_bytes) {
> + info->garbage_bytes--;
> + continue;
> + }
> + if (info->rx_skb == NULL) {
> + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
> + GFP_ATOMIC | GFP_DMA);
> + if (!info->rx_skb) {
> + dev_err(info->dev,
> + "No memory for new packet\n");
> + goto finish_rx;
> + }
> + info->rx_state = WAIT_FOR_PKT_TYPE;
> + info->rx_skb->dev = (void *)info->hdev;
> + }
> + info->hdev->stat.byte_rx++;
> + h4p_handle_byte(info, byte);
> + }
> +
> + if (!info->rx_enabled) {
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
> + info->autorts) {
> + __h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS);
> + info->autorts = 0;
> + }
> + /* Flush posted write to avoid spurious interrupts */
> + h4p_inb(info, UART_OMAP_SCR);
> + h4p_set_clk(info, &info->rx_clocks_en, 0);
> + }
> +
> +finish_rx:
> + BT_DBG("rx_ended");
> +}
> +
> +static void h4p_tx_tasklet(unsigned long data)
> +{
> + unsigned int sent = 0;
> + struct sk_buff *skb;
> + struct h4p_info *info = (struct h4p_info *)data;
> +
> + BT_DBG("tasklet woke up");
> + BT_DBG("tx_tasklet woke up");
Doubled?
> + if (info->autorts != info->rx_enabled) {
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
> + if (info->autorts && !info->rx_enabled) {
> + __h4p_set_auto_ctsrts(info, 0,
> + UART_EFR_RTS);
> + info->autorts = 0;
> + }
> + if (!info->autorts && info->rx_enabled) {
> + __h4p_set_auto_ctsrts(info, 1,
> + UART_EFR_RTS);
> + info->autorts = 1;
> + }
> + } else {
> + h4p_outb(info, UART_OMAP_SCR,
> + h4p_inb(info, UART_OMAP_SCR) |
> + UART_OMAP_SCR_EMPTY_THR);
> + goto finish_tx;
> + }
> + }
> +
> + skb = skb_dequeue(&info->txq);
> + if (!skb) {
> + /* No data in buffer */
> + BT_DBG("skb ready");
> + if (h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
> + h4p_outb(info, UART_IER,
> + h4p_inb(info, UART_IER) &
> + ~UART_IER_THRI);
> + h4p_inb(info, UART_OMAP_SCR);
> + h4p_disable_tx(info);
> + return;
> + }
> + h4p_outb(info, UART_OMAP_SCR,
> + h4p_inb(info, UART_OMAP_SCR) |
> + UART_OMAP_SCR_EMPTY_THR);
> + goto finish_tx;
> + }
> +
> + /* Copy data to tx fifo */
> + while (!(h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
> + (sent < skb->len)) {
> + //printk("[Out: %02x]", skb->data[sent]);
> + //printk("%02x ", skb->data[sent]);
> + h4p_outb(info, UART_TX, skb->data[sent]);
> + sent++;
> + }
> +
> + info->hdev->stat.byte_tx += sent;
> + if (skb->len == sent) {
> + kfree_skb(skb);
> + } else {
> + skb_pull(skb, sent);
> + skb_queue_head(&info->txq, skb);
> + }
> +
> + h4p_outb(info, UART_OMAP_SCR, h4p_inb(info, UART_OMAP_SCR) &
> + ~UART_OMAP_SCR_EMPTY_THR);
> + h4p_outb(info, UART_IER, h4p_inb(info, UART_IER) |
> + UART_IER_THRI);
> +
> +finish_tx:
> + /* Flush posted write to avoid spurious interrupts */
> + h4p_inb(info, UART_OMAP_SCR);
> +
> +}
next prev parent reply other threads:[~2014-12-15 10:01 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-12-13 22:37 bluetooth: Add hci_h4p driver Pavel Machek
2014-12-13 22:37 ` Pavel Machek
2014-12-13 23:30 ` Marcel Holtmann
2014-12-13 23:30 ` Marcel Holtmann
2014-12-13 23:51 ` Pavel Machek
2014-12-13 23:51 ` Pavel Machek
2014-12-14 0:07 ` Marcel Holtmann
2014-12-14 0:07 ` Marcel Holtmann
2014-12-14 9:47 ` Pavel Machek
2014-12-14 9:47 ` Pavel Machek
2014-12-14 10:40 ` Pavel Machek
2014-12-14 10:40 ` Pavel Machek
2014-12-14 10:40 ` Pavel Machek
2014-12-14 13:18 ` Bastien Nocera
2014-12-14 11:16 ` Pavel Machek
2014-12-14 11:16 ` Pavel Machek
2014-12-14 19:21 ` Pavel Machek
2014-12-14 19:21 ` Pavel Machek
2014-12-14 19:21 ` Pavel Machek
2014-12-14 20:28 ` Marcel Holtmann
2014-12-14 20:28 ` Marcel Holtmann
2014-12-14 22:41 ` Pavel Machek
2014-12-14 22:41 ` Pavel Machek
2014-12-14 22:41 ` Pavel Machek
2014-12-14 21:52 ` Pavel Machek
2014-12-14 21:52 ` Pavel Machek
2014-12-15 10:01 ` Oliver Neukum [this message]
2014-12-15 10:01 ` Oliver Neukum
2014-12-18 19:31 ` Pavel Machek
2014-12-18 19:31 ` Pavel Machek
2014-12-18 20:10 ` Pavel Machek
2014-12-18 20:10 ` Pavel Machek
2014-12-15 12:10 ` Marcel Holtmann
2014-12-15 12:10 ` Marcel Holtmann
2014-12-19 9:50 ` Pavel Machek
2014-12-19 9:50 ` Pavel Machek
2014-12-19 9:58 ` Marcel Holtmann
2014-12-19 9:58 ` Marcel Holtmann
2014-12-20 15:48 ` Pavel Machek
2014-12-20 15:48 ` Pavel Machek
2014-12-20 23:39 ` Marcel Holtmann
2014-12-20 23:39 ` Marcel Holtmann
2014-12-20 20:23 ` [PATCH] " Pavel Machek
2014-12-20 20:23 ` Pavel Machek
2014-12-20 20:23 ` Pavel Machek
2014-12-20 20:43 ` Paul Bolle
2014-12-20 20:43 ` Paul Bolle
2014-12-20 23:35 ` Marcel Holtmann
2014-12-20 23:35 ` Marcel Holtmann
2014-12-23 12:00 ` Pavel Machek
2014-12-23 12:00 ` Pavel Machek
2014-12-23 12:41 ` Pavel Machek
2014-12-23 12:41 ` Pavel Machek
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=1418637710.4443.11.camel@linux-0dmf.site \
--to=oneukum@suse.de \
--cc=aaro.koskinen@iki.fi \
--cc=ivo.g.dimitrov.75@gmail.com \
--cc=khilman@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-omap@vger.kernel.org \
--cc=marcel@holtmann.org \
--cc=pali.rohar@gmail.com \
--cc=pavel@ucw.cz \
--cc=sre@debian.org \
--cc=sre@ring0.de \
--cc=tony@atomide.com \
/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.