diff options
| author | wonhee <wonhee48.seo@samsung.com> | 2011-08-12 03:35:50 -0700 |
|---|---|---|
| committer | Benoit Goby <benoit@android.com> | 2011-08-12 14:15:03 -0700 |
| commit | 17e32f463b790dd539cde6daef6711a94f64206a (patch) | |
| tree | 6ca06d75018ab68d859626ff89c8b527c84be2ed /drivers | |
| parent | 555c7ee2d929f634f896cb5a65bedbd7ae61984a (diff) | |
| download | kernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.tar.gz kernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.tar.bz2 kernel_samsung_tuna-17e32f463b790dd539cde6daef6711a94f64206a.zip | |
misc: modem_if: Add NET bridge driver
1. Add net bridge driver.
- modem_bridge_device.c
2. Add handling net data for tx and rx in io device.
- need to include ether header structure
3. Requirement for bridge driver.
a. need ril binary which is enabled bridge func
b. need radio permission for '/dev/modem_br'
: ril needs to flow control, protocol-suspend(stop) and protocol-resume(start)
: this is for ioctl func that ril will access
c. tuna_defconfig
: 'CONFIG_BRIDGE=y' => 802.1d Ethernet Bridging
: '# CONFIG_BRIDGE_IGMP_SNOOPING is not set' => to prevent ip4 packet data goes IPv6 only PDN, cannot get ipv6 address
4. Use platform data to check network type. - patch set 2.
5. Change modem_bridge_device.c -> modem_net_flowcontrol_device.c - patch set 3
- remove unnecessary dummy net device
6. Not use CONFIG_BRIDGE in io_device code.
- use platform data
7. Change suspend/resume ioctl command number. - patch set 4
- need to update ril
Change-Id: I2c7b4bb53bad154f52b39ccf4d0d3133d055361a
Signed-off-by: wonhee <wonhee48.seo@samsung.com>
Diffstat (limited to 'drivers')
| -rwxr-xr-x | drivers/misc/modem_if/Makefile | 2 | ||||
| -rw-r--r-- | drivers/misc/modem_if/modem.c | 6 | ||||
| -rwxr-xr-x | drivers/misc/modem_if/modem_io_device.c | 62 | ||||
| -rwxr-xr-x | drivers/misc/modem_if/modem_net_flowcontrol_device.c | 115 | ||||
| -rwxr-xr-x | drivers/misc/modem_if/modem_prj.h | 11 |
5 files changed, 189 insertions, 7 deletions
diff --git a/drivers/misc/modem_if/Makefile b/drivers/misc/modem_if/Makefile index d2d0d5b7a63..e76c8b28a18 100755 --- a/drivers/misc/modem_if/Makefile +++ b/drivers/misc/modem_if/Makefile @@ -1,4 +1,4 @@ -obj-y += modem.o modem_io_device.o lte_modem_bootloader.o +obj-y += modem.o modem_io_device.o modem_net_flowcontrol_device.o obj-$(CONFIG_UMTS_MODEM_XMM6260) += modem_modemctl_device_xmm6260.o obj-$(CONFIG_UMTS_LINK_MIPI) += modem_link_device_mipi.o obj-$(CONFIG_UMTS_LINK_HSIC) += modem_link_device_hsic.o diff --git a/drivers/misc/modem_if/modem.c b/drivers/misc/modem_if/modem.c index 0642b238e8b..3d5bd0c8fe5 100644 --- a/drivers/misc/modem_if/modem.c +++ b/drivers/misc/modem_if/modem.c @@ -67,7 +67,7 @@ static struct modem_ctl *create_modemctl_device(struct platform_device *pdev) } static struct io_device *create_io_device(struct modem_io_t *io_t, - struct modem_ctl *modemctl) + struct modem_ctl *modemctl, enum modem_network modem_net) { int ret = 0; struct io_device *iod = NULL; @@ -82,6 +82,7 @@ static struct io_device *create_io_device(struct modem_io_t *io_t, iod->id = io_t->id; iod->format = io_t->format; iod->io_typ = io_t->io_type; + iod->net_typ = modem_net; /* link between io device and modem control */ iod->mc = modemctl; @@ -126,7 +127,8 @@ static int __devinit modem_probe(struct platform_device *pdev) /* create io deivces and connect to modemctl device */ for (i = 0; i < pdata->num_iodevs; i++) { - iod[i] = create_io_device(&pdata->iodevs[i], modemctl); + iod[i] = create_io_device(&pdata->iodevs[i], modemctl, + pdata->modem_net); if (!iod[i]) goto err_free_modemctl; diff --git a/drivers/misc/modem_if/modem_io_device.c b/drivers/misc/modem_if/modem_io_device.c index 8ce60d89b85..f1c9fe30e95 100755 --- a/drivers/misc/modem_if/modem_io_device.c +++ b/drivers/misc/modem_if/modem_io_device.c @@ -22,6 +22,7 @@ #include <linux/gpio.h> #include <linux/if_arp.h> #include <linux/ip.h> +#include <linux/if_ether.h> #include <linux/platform_data/modem.h> #include "modem_prj.h" @@ -243,6 +244,20 @@ static int rx_hdlc_data_check(struct io_device *iod, char *buf, unsigned rest) /* copy the RFS haeder to skb->data */ memcpy(skb_put(skb, head_size), hdr->hdr, head_size); break; + + case IPC_MULTI_RAW: + if (iod->net_typ == UMTS_NETWORK) + skb = alloc_skb(alloc_size, GFP_ATOMIC); + else + skb = alloc_skb(alloc_size + + sizeof(struct ethhdr), GFP_ATOMIC); + if (unlikely(!skb)) + return -ENOMEM; + + if (iod->net_typ != UMTS_NETWORK) + skb_reserve(skb, sizeof(struct ethhdr)); + break; + default: skb = alloc_skb(alloc_size, GFP_ATOMIC); if (unlikely(!skb)) @@ -295,6 +310,9 @@ static int rx_iodev_skb_raw(struct io_device *iod) struct sk_buff *skb = iod->skb_recv; struct net_device *ndev; struct iphdr *ip_header; + struct ethhdr *ehdr; + const char source[ETH_ALEN] = SOURCE_MAC_ADDR; + const char dest[ETH_ALEN] = {BRIDGE_MAC_ADDR, 0, 0, 0, 0, 0}; switch (iod->io_typ) { case IODEV_MISC: @@ -318,7 +336,21 @@ static int rx_iodev_skb_raw(struct io_device *iod) else skb->protocol = htons(ETH_P_IP); - err = netif_rx(skb); + if (iod->net_typ == UMTS_NETWORK) + err = netif_rx(skb); + else { + skb_push(skb, sizeof(struct ethhdr)); + ehdr = (void *)skb->data; + memcpy(ehdr->h_dest, dest, ETH_ALEN); + memcpy(ehdr->h_source, source, ETH_ALEN); + ehdr->h_proto = skb->protocol; + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_reset_mac_header(skb); + + skb_pull(skb, sizeof(struct ethhdr)); + err = netif_rx_ni(skb); + } + if (err != NET_RX_SUCCESS) dev_err(&ndev->dev, "rx error: %d\n", err); return err; @@ -702,6 +734,13 @@ static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev) struct vnet *vnet = netdev_priv(ndev); struct io_device *iod = vnet->iod; + /* umts doesn't need to discard ethernet header */ + if (iod->net_typ != UMTS_NETWORK) { + if (iod->id >= PSD_DATA_CHID_BEGIN && + iod->id <= PSD_DATA_CHID_END) + skb_pull(skb, sizeof(struct ethhdr)); + } + hd.len = skb->len + sizeof(hd); hd.control = 0; hd.channel = iod->id & 0x1F; @@ -743,8 +782,21 @@ static void vnet_setup(struct net_device *ndev) ndev->netdev_ops = &vnet_ops; ndev->type = ARPHRD_PPP; ndev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - ndev->hard_header_len = 0; ndev->addr_len = 0; + ndev->hard_header_len = 0; + ndev->tx_queue_len = 1000; + ndev->mtu = ETH_DATA_LEN; + ndev->watchdog_timeo = 5 * HZ; +} + +static void vnet_setup_ether(struct net_device *ndev) +{ + ndev->netdev_ops = &vnet_ops; + ndev->type = ARPHRD_ETHER; + ndev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST | IFF_SLAVE; + ndev->addr_len = ETH_ALEN; + ndev->dev_addr[0] = BRIDGE_MAC_ADDR; + ndev->hard_header_len = 0; ndev->tx_queue_len = 1000; ndev->mtu = ETH_DATA_LEN; ndev->watchdog_timeo = 5 * HZ; @@ -780,7 +832,11 @@ int init_io_device(struct io_device *iod) break; case IODEV_NET: - iod->ndev = alloc_netdev(0, iod->name, vnet_setup); + if (iod->net_typ == UMTS_NETWORK) + iod->ndev = alloc_netdev(0, iod->name, vnet_setup); + else + iod->ndev = alloc_netdev(0, iod->name, + vnet_setup_ether); if (!iod->ndev) { pr_err("failed to alloc netdev\n"); return -ENOMEM; diff --git a/drivers/misc/modem_if/modem_net_flowcontrol_device.c b/drivers/misc/modem_if/modem_net_flowcontrol_device.c new file mode 100755 index 00000000000..9397eddf7e1 --- /dev/null +++ b/drivers/misc/modem_if/modem_net_flowcontrol_device.c @@ -0,0 +1,115 @@ +/* /linux/drivers/misc/modem_if/modem_net_flowcontrol_device.c + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2011 Samsung Electronics. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/sched.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/platform_data/modem.h> + +#include "modem_prj.h" + + +#define NET_FLOWCONTROL_DEV_NAME_LEN 8 + +static int modem_net_flowcontrol_device_open( + struct inode *inode, struct file *filp) +{ + return 0; +} + +static int modem_net_flowcontrol_device_release( + struct inode *inode, struct file *filp) +{ + return 0; +} + +static long modem_net_flowcontrol_device_ioctl( + struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct net *this_net; + struct net_device *ndev; + char dev_name[NET_FLOWCONTROL_DEV_NAME_LEN]; + u8 chan; + + if (copy_from_user(&chan, (void __user *)arg, sizeof(char))) + return -EFAULT; + + if (chan > 15) + return -ENODEV; + + snprintf(dev_name, NET_FLOWCONTROL_DEV_NAME_LEN, "rmnet%d", (int)chan); + this_net = get_net_ns_by_pid(current->pid); + ndev = __dev_get_by_name(this_net, dev_name); + if (ndev == NULL) { + pr_err("[MODEM_IF] %s: device = %s not exist\n", __func__, + dev_name); + return -ENODEV; + } + + switch (cmd) { + case IOCTL_MODEM_NET_SUSPEND: + netif_stop_queue(ndev); + pr_info("[MODEM_IF] NET SUSPEND(%s)\n", dev_name); + break; + case IOCTL_MODEM_NET_RESUME: + netif_wake_queue(ndev); + pr_info("[MODEM_IF] NET RESUME(%s)\n", dev_name); + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct file_operations modem_net_flowcontrol_device_fops = { + .owner = THIS_MODULE, + .open = modem_net_flowcontrol_device_open, + .release = modem_net_flowcontrol_device_release, + .unlocked_ioctl = modem_net_flowcontrol_device_ioctl, +}; + +static int __init modem_net_flowcontrol_device_init(void) +{ + int ret = 0; + struct io_device *net_flowcontrol_dev; + + net_flowcontrol_dev = kzalloc(sizeof(struct io_device), GFP_KERNEL); + if (!net_flowcontrol_dev) { + pr_err("[MODEM_IF] net_flowcontrol_dev io device memory alloc fail\n"); + return -ENOMEM; + } + + net_flowcontrol_dev->miscdev.minor = MISC_DYNAMIC_MINOR; + net_flowcontrol_dev->miscdev.name = "modem_br"; + net_flowcontrol_dev->miscdev.fops = &modem_net_flowcontrol_device_fops; + + ret = misc_register(&net_flowcontrol_dev->miscdev); + if (ret) + pr_err("[MODEM_IF] failed to register misc br device : %s\n", + net_flowcontrol_dev->miscdev.name); + + return ret; +} + +module_init(modem_net_flowcontrol_device_init); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Samsung Modem IF Net Flowcontrol Driver"); diff --git a/drivers/misc/modem_if/modem_prj.h b/drivers/misc/modem_if/modem_prj.h index 2ca9f7679fc..79a5d8002f8 100755 --- a/drivers/misc/modem_if/modem_prj.h +++ b/drivers/misc/modem_if/modem_prj.h @@ -35,10 +35,12 @@ #define IOCTL_MODEM_SEND _IO('o', 0x25) #define IOCTL_MODEM_RECV _IO('o', 0x26) -#define IOCTL_MODEM_STATUS _IO('o', 0x27) +#define IOCTL_MODEM_STATUS _IO('o', 0x27) #define IOCTL_MODEM_GOTA_START _IO('o', 0x28) #define IOCTL_MODEM_FW_UPDATE _IO('o', 0x29) +#define IOCTL_MODEM_NET_SUSPEND _IO('o', 0x30) +#define IOCTL_MODEM_NET_RESUME _IO('o', 0x31) /* modem status */ #define MODEM_OFF 0 @@ -52,8 +54,14 @@ #define IPC_HEADER_MAX_SIZE 6 /* fmt 3, raw 6, rfs 6 */ +#define PSD_DATA_CHID_BEGIN 0x2A +#define PSD_DATA_CHID_END 0x38 + #define IP6VERSION 6 +#define BRIDGE_MAC_ADDR 0x12 +#define SOURCE_MAC_ADDR {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC} + /* Does modem ctl structure will use state ? or status defined below ?*/ enum modem_state { STATE_OFFLINE, @@ -103,6 +111,7 @@ struct io_device { unsigned id; enum dev_format format; enum modem_io io_typ; + enum modem_network net_typ; struct sk_buff_head sk_rx_q; |
