diff options
Diffstat (limited to 'drivers/net/sipc/core.c')
-rw-r--r-- | drivers/net/sipc/core.c | 198 |
1 files changed, 118 insertions, 80 deletions
diff --git a/drivers/net/sipc/core.c b/drivers/net/sipc/core.c index c8045b69222c..34135d85de58 100644 --- a/drivers/net/sipc/core.c +++ b/drivers/net/sipc/core.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ -// -// Common code for Samsung IPC v4.x modems. -// -// Copyright (C) 2018 Simon Shields <simon@lineageos.org> -// +/* + * Common code for Samsung IPC v4.x modems. + * + * Copyright (C) 2018 Simon Shields <simon@lineageos.org> + */ + #include <dt-bindings/net/samsung_ipc.h> #include <linux/ip.h> #include <linux/miscdevice.h> @@ -18,8 +19,7 @@ #define LINK_CMD_STOP_RAW ((unsigned short)(0x00ca)) #define LINK_CMD_START_RAW ((unsigned short)(0x00cb)) -/* - * how this should work: +/* how this should work: * DT has io devices: format, name, channel, io type * this module registers the interfaces and provides an API for USB devices * (and eventually others) to provide the transport layer. @@ -30,8 +30,8 @@ * link device are made. */ -struct sipc_link *cur_links[SAMSUNG_IPC_FORMAT_MAX] = {NULL}; -struct sipc_link_callback *callbacks = NULL; +struct sipc_link *cur_links[SAMSUNG_IPC_FORMAT_MAX]; +struct sipc_link_callback *callbacks; int sipc_set_link(struct sipc_link *link, unsigned int type) { @@ -60,21 +60,24 @@ void sipc_clear_link(unsigned int type) } EXPORT_SYMBOL_GPL(sipc_clear_link); -static struct sipc_io_channel *find_io_channel(struct samsung_ipc *sipc, int channel, +static struct sipc_io_channel *find_io_channel(struct samsung_ipc *sipc, + int channel, int format) { int i; for (i = 0; i < sipc->nchannels; i++) { if (sipc->channels[i].format == format) { - if (channel == -1 || sipc->channels[i].channel == channel) + if (channel == -1 || + sipc->channels[i].channel == channel) return &sipc->channels[i]; } } return NULL; } -int sipc_get_header_size(int format) { +int sipc_get_header_size(int format) +{ switch (format) { case SAMSUNG_IPC_FORMAT_FMT: return sizeof(struct fmt_header); @@ -88,7 +91,8 @@ int sipc_get_header_size(int format) { } } -static int sipc_hdlc_header_check(struct hdlc_header *hdr, char *buf, size_t bufsz, int format) +static int sipc_hdlc_header_check(struct hdlc_header *hdr, + char *buf, size_t bufsz, int format) { int len = 0; int done = 0; @@ -122,7 +126,8 @@ static int sipc_get_message_size(struct sipc_io_channel *chan) switch (chan->format) { case SAMSUNG_IPC_FORMAT_FMT: if (chan->sipc->version == SAMSUNG_IPC_VERSION_42) - return chan->pending_rx_header.sipc_header.fmt.len & 0x3fff; + return chan->pending_rx_header.sipc_header.fmt.len & + 0x3fff; return chan->pending_rx_header.sipc_header.fmt.len; case SAMSUNG_IPC_FORMAT_RAW: case SAMSUNG_IPC_FORMAT_MULTI_RAW: @@ -136,7 +141,8 @@ static int sipc_get_message_size(struct sipc_io_channel *chan) static void sipc_netdev_rx(struct work_struct *work) { - struct sipc_io_channel *chan = container_of(work, struct sipc_io_channel, + struct sipc_io_channel *chan = container_of(work, + struct sipc_io_channel, raw_rx_work.work); struct sk_buff *skb; struct net_device *ndev = chan->netdev; @@ -164,15 +170,14 @@ static void sipc_netdev_rx(struct work_struct *work) dev_err(&ndev->dev, "failed to rx packet: %d\n", ret); dev_kfree_skb_any(skb); /* try rx again in a bit... */ - schedule_delayed_work(&chan->raw_rx_work, msecs_to_jiffies(500)); + schedule_delayed_work(&chan->raw_rx_work, + msecs_to_jiffies(500)); break; } } } -/* - * Demultiplex multiplexed network data. - */ +/* Demultiplex multiplexed network data. */ static int do_raw_rx(struct sk_buff *skb, struct sipc_io_channel *chan) { u8 id; @@ -181,9 +186,11 @@ static int do_raw_rx(struct sk_buff *skb, struct sipc_io_channel *chan) id = hdr->channel; - real_chan = find_io_channel(chan->sipc, 0x20 | id, SAMSUNG_IPC_FORMAT_RAW); + real_chan = find_io_channel(chan->sipc, + 0x20 | id, SAMSUNG_IPC_FORMAT_RAW); if (!real_chan) { - dev_err(chan->sipc->dev, "Invalid raw multipdp channel %#x\n", id); + dev_err(chan->sipc->dev, + "Invalid raw multipdp channel %#x\n", id); return -ENODEV; } @@ -195,7 +202,7 @@ static int do_raw_rx(struct sk_buff *skb, struct sipc_io_channel *chan) return 0; } -#define SIPC_FMT_MORE_FRAMES (1 << 7) +#define SIPC_FMT_MORE_FRAMES BIT(7) static int do_fmt_rx(struct sk_buff *rx_skb, struct sipc_io_channel *chan) { struct fmt_header *hdr = &chan->pending_rx_header.sipc_header.fmt; @@ -211,19 +218,19 @@ static int do_fmt_rx(struct sk_buff *rx_skb, struct sipc_io_channel *chan) skb_queue_tail(&chan->rx_queue, rx_skb); wake_up(&chan->wq); return 0; - } else { - skb = alloc_skb(MAX_MULTI_RX_SIZE, GFP_KERNEL); - if (!skb) - return -ENOMEM; + } - chan->fmt_skb[id] = skb; + skb = alloc_skb(MAX_MULTI_RX_SIZE, GFP_KERNEL); + if (!skb) + return -ENOMEM; - if (len < sizeof(*hdr)) { - dev_err(chan->sipc->dev, "Header too short!\n"); - return -EINVAL; - } - hdr = (struct fmt_header *)data; + chan->fmt_skb[id] = skb; + + if (len < sizeof(*hdr)) { + dev_err(chan->sipc->dev, "Header too short!\n"); + return -EINVAL; } + hdr = (struct fmt_header *)data; } memcpy(skb_put(skb, len), data, len); @@ -245,7 +252,8 @@ static int sipc_do_rx(struct sk_buff *skb, struct sipc_io_channel *chan) switch (chan->format) { case SAMSUNG_IPC_FORMAT_FMT: if (chan->sipc->version == SAMSUNG_IPC_VERSION_42) - dev_warn(chan->sipc->dev, "Don't support IPC version 42 yet\n"); + dev_warn(chan->sipc->dev, + "Don't support IPC version 42 yet\n"); else return do_fmt_rx(skb, chan); return 0; @@ -256,7 +264,6 @@ static int sipc_do_rx(struct sk_buff *skb, struct sipc_io_channel *chan) wake_up(&chan->wq); return 0; } - } static void sipc_rx_cmd(struct samsung_ipc *sipc, void *buf, size_t bufsz) @@ -269,7 +276,8 @@ static void sipc_rx_cmd(struct samsung_ipc *sipc, void *buf, size_t bufsz) switch (*cmd) { case LINK_CMD_STOP_RAW: for (i = 0; i < sipc->nchannels; i++) { - if (sipc->channels[i].netdev && sipc->channels[i].type == SAMSUNG_IPC_TYPE_NETDEV) { + if (sipc->channels[i].netdev && sipc->channels[i].type == + SAMSUNG_IPC_TYPE_NETDEV) { netif_stop_queue(sipc->channels[i].netdev); } } @@ -279,7 +287,9 @@ static void sipc_rx_cmd(struct samsung_ipc *sipc, void *buf, size_t bufsz) break; case LINK_CMD_START_RAW: for (i = 0; i < sipc->nchannels; i++) { - if (sipc->channels[i].netdev && sipc->channels[i].type == SAMSUNG_IPC_TYPE_NETDEV) { + if (sipc->channels[i].netdev && + sipc->channels[i].type == + SAMSUNG_IPC_TYPE_NETDEV) { netif_start_queue(sipc->channels[i].netdev); } } @@ -288,13 +298,16 @@ static void sipc_rx_cmd(struct samsung_ipc *sipc, void *buf, size_t bufsz) complete_all(&sipc->raw_tx_resumed); break; default: - dev_info(sipc->dev, "Unknown flow control command %#x\n", *cmd); + dev_info(sipc->dev, + "Unknown flow control command %#x\n", *cmd); break; } } } -static int sipc_do_tx(struct samsung_ipc *sipc, struct sk_buff *skb, int format) { +static int sipc_do_tx(struct samsung_ipc *sipc, + struct sk_buff *skb, int format) +{ struct sipc_link *link; int ret; @@ -303,11 +316,11 @@ static int sipc_do_tx(struct samsung_ipc *sipc, struct sk_buff *skb, int format) goto exit; } - if (format == SAMSUNG_IPC_FORMAT_RAW || format == SAMSUNG_IPC_FORMAT_MULTI_RAW) { + if (format == SAMSUNG_IPC_FORMAT_RAW || + format == SAMSUNG_IPC_FORMAT_MULTI_RAW) { if (unlikely(sipc->raw_tx_suspended)) { - if (in_irq()) { + if (in_irq()) return -EBUSY; - } } wait_for_completion(&sipc->raw_tx_resumed); } @@ -316,18 +329,21 @@ static int sipc_do_tx(struct samsung_ipc *sipc, struct sk_buff *skb, int format) ret = link->transmit(link, skb); exit: - if (ret == -ENODEV || ret == -ENOENT) { + if (ret == -ENODEV || ret == -ENOENT) dev_kfree_skb_any(skb); - } return ret; } -static void sipc_tx_work(struct work_struct *work) { - struct samsung_ipc *sipc = container_of(work, struct samsung_ipc, tx_work.work); +static void sipc_tx_work(struct work_struct *work) +{ + struct samsung_ipc *sipc = container_of(work, + struct samsung_ipc, + tx_work.work); struct sk_buff *skb; int ret = 0; - while (sipc->tx_queue_rfs.qlen || sipc->tx_queue_fmt.qlen || sipc->tx_queue_raw.qlen) { + while (sipc->tx_queue_rfs.qlen || sipc->tx_queue_fmt.qlen || + sipc->tx_queue_raw.qlen) { // TODO: runtime PM skb = skb_dequeue(&sipc->tx_queue_rfs); if (skb) @@ -367,7 +383,7 @@ static void sipc_tx_work(struct work_struct *work) { } static int sipc_receive_callback(struct sipc_link_callback *cb, void *b, - size_t bufsz, int format) + size_t bufsz, int format) { struct samsung_ipc *sipc = cb_to_ipc(cb); struct sipc_io_channel *chan = find_io_channel(sipc, -1, format); @@ -383,7 +399,9 @@ static int sipc_receive_callback(struct sipc_link_callback *cb, void *b, } if (!chan) { - dev_err(sipc->dev, "Couldn't find channel with format=%d. Dropping packet!\n", format); + dev_err(sipc->dev, + "Couldn't find channel with format=%d. Dropping packet!\n", + format); return -ENOENT; } @@ -392,7 +410,8 @@ static int sipc_receive_callback(struct sipc_link_callback *cb, void *b, goto skip_header_check; next_frame: - len = sipc_hdlc_header_check(&chan->pending_rx_header, buf, bufsz, format); + len = sipc_hdlc_header_check(&chan->pending_rx_header, + buf, bufsz, format); if (len < 0) { dev_err(sipc->dev, "Invalid message format=%d\n", format); return -EINVAL; @@ -416,35 +435,33 @@ skip_header_check: /* TODO: what happens if we fail to allocate skbuff? */ if (!chan->pending_rx_skb) { - len = min(data_size, (size_t)MAX_RX_SIZE); + len = min_t(size_t, data_size, MAX_RX_SIZE); len = min(len, rest_size); if (format == SAMSUNG_IPC_FORMAT_RFS) { /* for RFS: separate header SKB */ skb = alloc_skb(header_size, GFP_KERNEL); - if (!skb) { - dev_err(sipc->dev, "Out of memory\n"); + if (!skb) return -ENOMEM; - } - memcpy(skb_put(skb, header_size), &chan->pending_rx_header.sipc_header.rfs, header_size); + memcpy(skb_put(skb, header_size), + &chan->pending_rx_header.sipc_header.rfs, + header_size); sipc_do_rx(skb, chan); } skb = alloc_skb(len, GFP_KERNEL); - if (!skb) { - dev_err(sipc->dev, "Out of memory\n"); + if (!skb) return -ENOMEM; - } chan->pending_rx_skb = skb; } /* line 331, sipc4_io_device.c */ while (bufsz > 0) { - len = min(bufsz, rest_size); - len = min(len, (size_t)skb_tailroom(chan->pending_rx_skb)); - len = min(len, (size_t)MAX_RX_SIZE); + len = min(size_t, bufsz, rest_size); + len = min_t(size_t, len, skb_tailroom(chan->pending_rx_skb)); + len = min_t(size_t, len, MAX_RX_SIZE); memcpy(skb_put(chan->pending_rx_skb, len), buf, len); @@ -460,7 +477,7 @@ skip_header_check: sipc_do_rx(chan->pending_rx_skb, chan); - len = min(rest_size, (size_t)MAX_RX_SIZE); + len = min_t(size_t, rest_size, MAX_RX_SIZE); skb = alloc_skb(len, GFP_KERNEL); if (!skb) { dev_err(sipc->dev, "Out of memory\n"); @@ -473,7 +490,9 @@ skip_header_check: dev_info(sipc->dev, "Processed %d bytes\n", done); if (!bufsz && chan->pending_rx_header.frag_len) { - /* Still waiting for end-of-packet. It will come in the next frame */ + /* Still waiting for end-of-packet. + * It will come in the next frame + */ return 0; } @@ -499,7 +518,7 @@ skip_header_check: } static int sipc_parse_dt(struct platform_device *pdev, - struct samsung_ipc *sipc) + struct samsung_ipc *sipc) { int count, ret; int i = 0; @@ -511,41 +530,54 @@ static int sipc_parse_dt(struct platform_device *pdev, return -EINVAL; } - sipc->channels = devm_kzalloc(&pdev->dev, sizeof(*sipc->channels) * count, GFP_KERNEL); + sipc->channels = devm_kzalloc(&pdev->dev, + sizeof(*sipc->channels) * count, + GFP_KERNEL); ret = of_property_read_u32(child, "protocol", &sipc->version); if (ret != 0) { - dev_warn(&pdev->dev, "Failed to read protocol version, assuming v4.0: %d\n", ret); + dev_warn(&pdev->dev, + "Failed to read protocol version, assuming v4.0: %d\n", + ret); sipc->version = SAMSUNG_IPC_VERSION_40; } for_each_available_child_of_node(np, child) { - - ret = of_property_read_u32(child, "reg", &sipc->channels[i].channel); + ret = of_property_read_u32(child, + "reg", &sipc->channels[i].channel); if (ret != 0 || !sipc->channels[i].channel) { - dev_err(&pdev->dev, "Couldn't read channel number: %d\n", - ret); + dev_err(&pdev->dev, + "Couldn't read channel number: %d\n", + ret); count--; continue; } - ret = of_property_read_u32(child, "type", &sipc->channels[i].type); - if (ret != 0 || sipc->channels[i].type >= SAMSUNG_IPC_TYPE_MAX) { - dev_err(&pdev->dev, "Coulnd't read channel type: %d\n", ret); + ret = of_property_read_u32(child, + "type", &sipc->channels[i].type); + if (ret != 0 || + sipc->channels[i].type >= SAMSUNG_IPC_TYPE_MAX) { + dev_err(&pdev->dev, + "Coulnd't read channel type: %d\n", ret); count--; continue; } - ret = of_property_read_u32(child, "format", &sipc->channels[i].format); - if (ret != 0 || sipc->channels[i].format >= SAMSUNG_IPC_FORMAT_MAX) { - dev_err(&pdev->dev, "Couldn't read channel format: %d\n", ret); + ret = of_property_read_u32(child, + "format", &sipc->channels[i].format); + if (ret != 0 || + sipc->channels[i].format >= SAMSUNG_IPC_FORMAT_MAX) { + dev_err(&pdev->dev, + "Couldn't read channel format: %d\n", ret); count--; continue; } - ret = of_property_read_string(child, "label", &sipc->channels[i].name); + ret = of_property_read_string(child, + "label", &sipc->channels[i].name); if (ret != 0) { - dev_err(&pdev->dev, "Couldn't read channel name: %d\n", ret); + dev_err(&pdev->dev, + "Couldn't read channel name: %d\n", ret); count--; continue; } @@ -602,17 +634,23 @@ static int sipc_probe(struct platform_device *pdev) ret = misc_register(&chan->miscdev); if (ret) - dev_err(sipc->dev, "Failed to register misc device '%s': %d\n", chan->name, + dev_err(sipc->dev, + "Failed to register misc device '%s': %d\n", + chan->name, ret); break; case SAMSUNG_IPC_TYPE_NETDEV: INIT_DELAYED_WORK(&chan->raw_rx_work, sipc_netdev_rx); skb_queue_head_init(&chan->rx_queue); chan->netdev = alloc_netdev(sizeof(struct sipc_netdev_priv), - chan->name, NET_NAME_UNKNOWN, sipc_netdev_setup); + chan->name, + NET_NAME_UNKNOWN, + sipc_netdev_setup); if (!chan->netdev) { - dev_err(sipc->dev, "Failed to alloc netdev %s\n", chan->name); + dev_err(sipc->dev, + "Failed to alloc netdev %s\n", + chan->name); return -ENOMEM; } |