Netdev List
 help / color / mirror / Atom feed
* Re: Gianfar ethernet drop package
From: Aníbal Almeida Pinto @ 2012-08-27 13:01 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1346065738.2420.135.camel@edumazet-glaptop>

Em 27-08-2012 12:08, Eric Dumazet escreveu:
> On Mon, 2012-08-27 at 11:32 +0100, Aníbal Almeida Pinto wrote:
>
>> I generate the log on the board with tcpdump -i eth0 -w log_eth0.txt and
>> loaded the result on wireshark (on other pc).
>>
>> On the wireshark everything appears to be fine don't have nothing that
>> indicate the protocol isn't supported.
>>
>> On /etc/protocols is a list with protocols, it there is a place where
>> exist a place with protocols supported by kernel ?
>
> So all frames understood by wireshark are also automatically handled by
> your linux machine ? That sounds cool, so we no longer have to add stuff
> in the kernel ?
>
> Let me explain again :
>
> For example, if you dont have IPv6 loaded, IPv6 frames wont be handled,
> and they appear to be dropped. They really are.
>
> If you run tcpdump/wireshark, these frames are at least delivered once
> to a sniffer, so they are not "dropped", even if no protocol handler
> actually reacts to them.

I understand your explanation.

My problem now is to identify why the packages were dropped.

Wireshark report what listen and with ifconfig I only know how many have 
been dropped.

I made a program, inline at the end, that tries to see the sockets that 
I can create on a system, that will give me a idea of what protocol 
handler that I have.

The program isn't complete and the options are a lot ...

Even with this I only can see the log of tcpdump and try to find frames 
that belong to protocols not supported, don't know if there isn't 
another reason, like Softnet backlog full or Bad / Unintended VLAN tags

Is there any way of put tcpdump or other tool to only log the packages 
dropped ?

Thanks

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>

#include <netdb.h>

#include <errno.h>

struct socket_conf {
	int socket_family; // domain
	int socket_type;
	int protocol;
};


struct socket_conf conf_list[] = {
	{ PF_LOCAL, SOCK_STREAM, 0 },	// Local stream socket
	{ PF_LOCAL, SOCK_DGRAM, 0 },	// Local datagram socket
	{ PF_INET, SOCK_STREAM, IPPROTO_TCP }, // TCP/IP stream socket
	{ PF_INET, SOCK_DGRAM, IPPROTO_UDP}, // UDP datagram socket
	{ PF_UNSPEC, SOCK_DGRAM , 0 },
	{ PF_LOCAL, SOCK_DGRAM , 0 },
	{ PF_UNIX, SOCK_DGRAM , 0 },
	{ PF_FILE, SOCK_DGRAM , 0 },
	{ PF_INET, SOCK_DGRAM , 0 },
//	{ PF_AX, SOCK_DGRAM , 0 },
	{ PF_IPX, SOCK_DGRAM , 0 },
	{ PF_APPLETALK, SOCK_DGRAM , 0 },
	{ PF_NETROM, SOCK_DGRAM , 0 },
	{ PF_BRIDGE, SOCK_DGRAM , 0 },
	{ PF_ATMPVC, SOCK_DGRAM , 0 },
//	{ PF_X, SOCK_DGRAM , 0 },
	{ PF_INET, SOCK_DGRAM , 0 },
	{ PF_ROSE, SOCK_DGRAM , 0 },
	{ PF_DECnet, SOCK_DGRAM , 0 },
	{ PF_NETBEUI, SOCK_DGRAM , 0 },
	{ PF_SECURITY, SOCK_DGRAM , 0 },
	{ PF_KEY, SOCK_DGRAM , 0 },
	{ PF_NETLINK , SOCK_DGRAM , 0 },
	{ PF_ROUTE , SOCK_DGRAM , 0 },
	{ PF_PACKET, SOCK_DGRAM , 0 },
	{ PF_ASH, SOCK_DGRAM , 0 },
	{ PF_ECONET, SOCK_DGRAM , 0 },
	{ PF_ATMSVC, SOCK_DGRAM , 0 },
	{ PF_SNA, SOCK_DGRAM , 0 },
	{ PF_IRDA, SOCK_DGRAM , 0 },
	{ PF_MAX, SOCK_DGRAM , 0 },
	{ AF_UNSPEC  , SOCK_DGRAM , 0 },
	{ AF_LOCAL  , SOCK_DGRAM , 0 },
	{ AF_UNIX  , SOCK_DGRAM , 0 },
	{ AF_FILE , SOCK_DGRAM , 0 },
	{ AF_INET, SOCK_DGRAM , 0 },
	{ AF_AX25, SOCK_DGRAM , 0 },
	{ AF_IPX , SOCK_DGRAM , 0 },
	{ AF_APPLETALK  , SOCK_DGRAM , 0 },
	{ AF_NETROM    , SOCK_DGRAM , 0 },
	{ AF_BRIDGE   , SOCK_DGRAM , 0 },
	{ AF_ATMPVC  , SOCK_DGRAM , 0 },
	{ AF_X25    , SOCK_DGRAM , 0 },
	{ AF_INET6 , SOCK_DGRAM , 0 },
	{ AF_ROSE   , SOCK_DGRAM , 0 },
	{ AF_DECnet  , SOCK_DGRAM , 0 },
	{ AF_NETBEUI  , SOCK_DGRAM , 0 },
	{ AF_SECURITY , SOCK_DGRAM , 0 },
//	{ pseudo_AF_KEY , SOCK_DGRAM , 0 },
	{ AF_NETLINK   , SOCK_DGRAM , 0 },
	{ AF_ROUTE    , SOCK_DGRAM , 0 },
	{ AF_PACKET  , SOCK_DGRAM , 0 },
	{ AF_ASH    , SOCK_DGRAM , 0 },
	{ AF_ECONET , SOCK_DGRAM , 0 },
	{ AF_ATMSVC , SOCK_DGRAM , 0 },
	{ AF_SNA   , SOCK_DGRAM , 0 },
	{ AF_IRDA , SOCK_DGRAM , 0 },
	{ AF_MAX  , SOCK_DGRAM , 0 },
};


int main(int argc, char * argv[]){

	int s, i;
	struct protoent * p;

	setprotoent(0);

	for(i = 0 ; i < sizeof(conf_list) / sizeof(struct socket_conf) ; i++) {

		p = getprotobynumber(conf_list[i].socket_family);

		printf("Index %d", i);

		if(p != NULL)
			printf(" prot %s", p->p_name);

		printf(" : ");	
				fflush(stdout);

		s = socket(conf_list[i].socket_family,
				conf_list[i].socket_type,
				conf_list[i].protocol
				);

		if( s == -1)
			perror("socket()");
		else
			printf("ok\n");

		fflush(stdout);
	}

	endprotoent();

	return 1;
}

^ permalink raw reply

* Re: [PATCH v2] libceph: Fix sparse warning
From: Iulius Curt @ 2012-08-27 12:20 UTC (permalink / raw)
  To: sage; +Cc: Iulius Curt, davem, ceph-devel, netdev, dbaluta
In-Reply-To: <1345724069-12405-1-git-send-email-icurt@ixiacom.com>

On 08/23/2012 03:14 PM, Iulius Curt wrote:
> From: Iulius Curt<iulius.curt@gmail.com>
>
> Make ceph_monc_do_poolop() static to remove the following sparse warning:
>   * net/ceph/mon_client.c:616:5: warning: symbol 'ceph_monc_do_poolop' was not
>     declared. Should it be static?
> Also drops the 'ceph_monc_' prefix, now being a private function.
>
> Signed-off-by: Iulius Curt<icurt@ixiacom.com>
> ---
> v1 --->  v2
>   * drop the 'ceph_monc_' prefix
> ---
>   net/ceph/mon_client.c |    6 +++---
>   1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
> index 105d533..84ce495 100644
> --- a/net/ceph/mon_client.c
> +++ b/net/ceph/mon_client.c
> @@ -613,7 +613,7 @@ bad:
>   /*
>    * Do a synchronous pool op.
>    */
> -int ceph_monc_do_poolop(struct ceph_mon_client *monc, u32 op,
> +static int do_poolop(struct ceph_mon_client *monc, u32 op,
>   			u32 pool, u64 snapid,
>   			char *buf, int len)
>   {
> @@ -663,7 +663,7 @@ out:
>   int ceph_monc_create_snapid(struct ceph_mon_client *monc,
>   			    u32 pool, u64 *snapid)
>   {
> -	return ceph_monc_do_poolop(monc,  POOL_OP_CREATE_UNMANAGED_SNAP,
> +	return do_poolop(monc,  POOL_OP_CREATE_UNMANAGED_SNAP,
>   				   pool, 0, (char *)snapid, sizeof(*snapid));
>
>   }
> @@ -672,7 +672,7 @@ EXPORT_SYMBOL(ceph_monc_create_snapid);
>   int ceph_monc_delete_snapid(struct ceph_mon_client *monc,
>   			    u32 pool, u64 snapid)
>   {
> -	return ceph_monc_do_poolop(monc,  POOL_OP_CREATE_UNMANAGED_SNAP,
> +	return do_poolop(monc,  POOL_OP_CREATE_UNMANAGED_SNAP,
>   				   pool, snapid, 0, 0);
>
>   }
> --
> 1.7.9.5
>
>
Hi Sage,

Can you, please, have a look.

Thanks,
Iulius


^ permalink raw reply

* Re[3]: [PATCH 2/3] ipvs: Fix faulty IPv6 extension header  handling in IPVS
From: Patrick McHardy @ 2012-08-27 12:02 UTC (permalink / raw)
  To: Hans Schillstrom
  Cc: Jesper Dangaard Brouer, netdev, lvs-devel, Julian Anastasov,
	Simon Horman, Wensong Zhang, netfilter-devel
In-Reply-To: <mdaatbj.7a4274ea6c8f14ea15788c8953acb422@obelix.schillstrom.com>

On Mon, 27 Aug 2012, Hans Schillstrom wrote:

>>>>
>>>> On Mon, 20 Aug 2012, Jesper Dangaard Brouer wrote:
>>>>
>>>>> Based on patch from: Hans Schillstrom
>>>>>
>>>>> IPv6 headers must be processed in order of appearance,
>>>>> neither can it be assumed that Upper layer headers is first.
>>>>> If anything else than L4 is the first header IPVS will throw it.
>>>>>
>>>>> IPVS will write SNAT & DNAT modifications at a fixed pos which
>>>>> will corrupt the message. Proper header position must be found
>>>>> before writing modifying packet.
>>>>>
>>>>> This patch contains a lot of API changes.  This is done, to avoid
>>>>> the costly scan of finding the IPv6 headers, via ipv6_find_hdr().
>>>>> Finding the IPv6 headers is done as early as possible, and passed
>>>>> on as a pointer "struct ip_vs_iphdr *" to the affected functions.
>>>>
>>>> How about we change netfilter to set up the skb's transport header
>>>> at an early time so we can avoid all (most of) these header scans
>>>> in netfilter?
>>>
>>> I think that would be great, maybe it should be global i.e. not only a netfilter issue.
>>
>> I think in most other cases the headers are supposed to be processed
>> sequentially. One problem though - to be useful for netfilter/IPVS
>> we'd also need to store the transport layer protocol somewhere.
>
> I guess that's the problem, adding it to the skb will not be popular ....
> Right now I don't have a good solution, maybe a more generic netfilter ptr in the skb ...

I guess inet6_skb_parm will be at least slightly more popular than
adding it to the skb itself. The netfilter pointers are all used for
optional things, so we can't really add it to any of those.

^ permalink raw reply

* Re[3]: [PATCH 2/3] ipvs: Fix faulty IPv6 extension header handling in IPVS
From: Hans Schillstrom @ 2012-08-27 11:58 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Jesper Dangaard Brouer, netdev, lvs-devel, Julian Anastasov,
	Simon Horman, Wensong Zhang, netfilter-devel

>>>
>>> On Mon, 20 Aug 2012, Jesper Dangaard Brouer wrote:
>>>
>>>> Based on patch from: Hans Schillstrom
>>>>
>>>> IPv6 headers must be processed in order of appearance,
>>>> neither can it be assumed that Upper layer headers is first.
>>>> If anything else than L4 is the first header IPVS will throw it.
>>>>
>>>> IPVS will write SNAT & DNAT modifications at a fixed pos which
>>>> will corrupt the message. Proper header position must be found
>>>> before writing modifying packet.
>>>>
>>>> This patch contains a lot of API changes.  This is done, to avoid
>>>> the costly scan of finding the IPv6 headers, via ipv6_find_hdr().
>>>> Finding the IPv6 headers is done as early as possible, and passed
>>>> on as a pointer "struct ip_vs_iphdr *" to the affected functions.
>>>
>>> How about we change netfilter to set up the skb's transport header
>>> at an early time so we can avoid all (most of) these header scans
>>> in netfilter?
>>
>> I think that would be great, maybe it should be global i.e. not only a netfilter issue.
>
>I think in most other cases the headers are supposed to be processed 
>sequentially. One problem though - to be useful for netfilter/IPVS
>we'd also need to store the transport layer protocol somewhere.

I guess that's the problem, adding it to the skb will not be popular ....
Right now I don't have a good solution, maybe a more generic netfilter ptr in the skb ...




^ permalink raw reply

* Re[2]:  [PATCH 2/3] ipvs: Fix faulty IPv6 extension header  handling in IPVS
From: Patrick McHardy @ 2012-08-27 11:13 UTC (permalink / raw)
  To: Hans Schillstrom
  Cc: Jesper Dangaard Brouer, netdev, lvs-devel, Julian Anastasov,
	Simon Horman, Wensong Zhang, netfilter-devel
In-Reply-To: <mdaatbj.ca5ac4e44d852a03ede087a5ed658cd9@obelix.schillstrom.com>

On Mon, 27 Aug 2012, Hans Schillstrom wrote:

>>
>> On Mon, 20 Aug 2012, Jesper Dangaard Brouer wrote:
>>
>>> Based on patch from: Hans Schillstrom
>>>
>>> IPv6 headers must be processed in order of appearance,
>>> neither can it be assumed that Upper layer headers is first.
>>> If anything else than L4 is the first header IPVS will throw it.
>>>
>>> IPVS will write SNAT & DNAT modifications at a fixed pos which
>>> will corrupt the message. Proper header position must be found
>>> before writing modifying packet.
>>>
>>> This patch contains a lot of API changes.  This is done, to avoid
>>> the costly scan of finding the IPv6 headers, via ipv6_find_hdr().
>>> Finding the IPv6 headers is done as early as possible, and passed
>>> on as a pointer "struct ip_vs_iphdr *" to the affected functions.
>>
>> How about we change netfilter to set up the skb's transport header
>> at an early time so we can avoid all (most of) these header scans
>> in netfilter?
>
> I think that would be great, maybe it should be global i.e. not only a netfilter issue.

I think in most other cases the headers are supposed to be processed 
sequentially. One problem though - to be useful for netfilter/IPVS
we'd also need to store the transport layer protocol somewhere.

^ permalink raw reply

* Re: Gianfar ethernet drop package
From: Eric Dumazet @ 2012-08-27 11:08 UTC (permalink / raw)
  To: Aníbal Almeida Pinto; +Cc: netdev
In-Reply-To: <503B4CBB.1020405@efacec.com>

On Mon, 2012-08-27 at 11:32 +0100, Aníbal Almeida Pinto wrote:

> I generate the log on the board with tcpdump -i eth0 -w log_eth0.txt and 
> loaded the result on wireshark (on other pc).
> 
> On the wireshark everything appears to be fine don't have nothing that 
> indicate the protocol isn't supported.
> 
> On /etc/protocols is a list with protocols, it there is a place where 
> exist a place with protocols supported by kernel ?

So all frames understood by wireshark are also automatically handled by
your linux machine ? That sounds cool, so we no longer have to add stuff
in the kernel ?

Let me explain again :

For example, if you dont have IPv6 loaded, IPv6 frames wont be handled,
and they appear to be dropped. They really are.

If you run tcpdump/wireshark, these frames are at least delivered once
to a sniffer, so they are not "dropped", even if no protocol handler
actually reacts to them.

^ permalink raw reply

* Re[2]:  [PATCH 2/3] ipvs: Fix faulty IPv6 extension header handling in IPVS
From: Hans Schillstrom @ 2012-08-27 10:55 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Jesper Dangaard Brouer, netdev, lvs-devel, Julian Anastasov,
	Simon Horman, Wensong Zhang, netfilter-devel

>
>On Mon, 20 Aug 2012, Jesper Dangaard Brouer wrote:
>
>> Based on patch from: Hans Schillstrom
>>
>> IPv6 headers must be processed in order of appearance,
>> neither can it be assumed that Upper layer headers is first.
>> If anything else than L4 is the first header IPVS will throw it.
>>
>> IPVS will write SNAT & DNAT modifications at a fixed pos which
>> will corrupt the message. Proper header position must be found
>> before writing modifying packet.
>>
>> This patch contains a lot of API changes.  This is done, to avoid
>> the costly scan of finding the IPv6 headers, via ipv6_find_hdr().
>> Finding the IPv6 headers is done as early as possible, and passed
>> on as a pointer "struct ip_vs_iphdr *" to the affected functions.
>
>How about we change netfilter to set up the skb's transport header
>at an early time so we can avoid all (most of) these header scans
>in netfilter?

I think that would be great, maybe it should be global i.e. not only a netfilter issue.


^ permalink raw reply

* Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling
From: Patrick McHardy @ 2012-08-27 10:41 UTC (permalink / raw)
  To: Jesper Dangaard Brouer
  Cc: netfilter-devel, netdev, Julian Anastasov, Hans Schillstrom,
	Hans Schillstrom
In-Reply-To: <1346062428.3069.398.camel@localhost>

On Mon, 27 Aug 2012, Jesper Dangaard Brouer wrote:

>>> When loading "nf_conntrack_ipv6" I run into issues.
>>>
>>> When sending a fragmented UDP packet.  With these patches, the IPVS
>>> stack will no longer see the fragmented packets, but instead see one
>>> large SKB.  This will trigger a MTU path check in e.g.
>>> ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.
>>>
>>>  IPVS: ip_vs_dr_xmit_v6(): frag needed
>>>
>>> Perhaps we could change/fix the MTU check in IPVS?
>>> (This would also solve issues I've seen with TSO/GSO frames, hitting
>>> this code path).
>>
>> I guess this should use the same check as in IPv6 output, check
>> whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send
>> an ICMPv6 error in that case.
>
> Hans have (already) proposed this solution:
>
>  if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
>      (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {
>
> And I have tested it works.
> But I'm not sure about, if we really need the "!skb->local_df" check ?

Not necessarily, alternatively you could use:

if ((!IP6CB(skb)->frag_max_size &&
      (skb->len > mtu && !skb_is_gso(skb)) ||
     IP6CB(skb)->frag_max_size > mtu)

We just need to make sure that if frag_max_size is set that skb->len
is ignored. Either way is fine, but I'd suggest to keep it similar to
the variant used in IPv6.

> Thus, we should extend you patchset with a patch, that also address the
> MTU checks in IPVS.

Can you send over a patch for inclusion in the patchset? Besides this, its
ready for submission.

^ permalink raw reply

* Re: Gianfar ethernet drop package
From: Aníbal Almeida Pinto @ 2012-08-27 10:32 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1345832223.19483.75.camel@edumazet-glaptop>

Em 24-08-2012 19:17, Eric Dumazet escreveu:
> On Fri, 2012-08-24 at 17:14 +0100, Aníbal Almeida Pinto wrote:
>> Hi,
>>
>> I have an board with a ppc with a 8379, kernel 3.0.39 and with a Gianfar
>> Ethernet Controller Version 1.2.
>>
>> When connect the board to office network the number of dropped packets
>> reported by ifconfig continues to increase.
>>
>> Following the test made at [1] I use tcpdump and when running it the
>> number of drop packages don't have increased.
>>
>> When executing ethtool eth0 -S it return a rx-dropped-by-kernel != 0.
>> And the rest of drop packages
>>
>> Is possible to get info why the packages are dropped?
>
> You receive frames for unknown protocols. So they are dropped.
>
> When running tcpdump, your tcpdump get them, they are not dropped.
>
> So just parse your tcpdump output ?
>

I generate the log on the board with tcpdump -i eth0 -w log_eth0.txt and 
loaded the result on wireshark (on other pc).

On the wireshark everything appears to be fine don't have nothing that 
indicate the protocol isn't supported.

On /etc/protocols is a list with protocols, it there is a place where 
exist a place with protocols supported by kernel ?

Thanks

^ permalink raw reply

* [net patch 0/2] bnx2x: Correct bnx2x operation with netpoll
From: Merav Sicron @ 2012-08-27 13:26 UTC (permalink / raw)
  To: davem, netdev, eilong; +Cc: Merav Sicron

Hi Dave,
This patch series corrects bnx2x operation with netpoll:
The first patch is to move the netif_napi_add to the open call to avoid napi
objects that are added but may not be later enabled.
The second patch corrects the poll_bnx2x function itself to also work with
MSI-X.

Please consider applying this patch series to net.

Thanks,
Merav

^ permalink raw reply

* [net patch 1/2] bnx2x: Move netif_napi_add to the open call
From: Merav Sicron @ 2012-08-27 13:26 UTC (permalink / raw)
  To: davem, netdev, eilong; +Cc: Merav Sicron, Dmitry Kravkov
In-Reply-To: <1346073980-30901-1-git-send-email-meravs@broadcom.com>

Move netif_napi_add for all queues from the probe call to the open call, to
avoid the case that napi objects are added for queues that may eventually not
be initialized and activated. With the former behavior, the driver could crash
when netpoll was calling ndo_poll_controller.

Signed-off-by: Merav Sicron <meravs@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x.h         |    3 ---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c     |    4 ++++
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h     |    4 ++--
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c |    2 --
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c    |   10 ++++------
 5 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 77bcd4c..a462cbc 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1708,9 +1708,6 @@ struct bnx2x_func_init_params {
 			continue;		\
 		else

-#define for_each_napi_rx_queue(bp, var) \
-	for ((var) = 0; (var) < bp->num_napi_queues; (var)++)
-
 /* Skip OOO FP */
 #define for_each_tx_queue(bp, var) \
 	for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index e879e19..af20c6e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -2046,6 +2046,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
 	 */
 	bnx2x_setup_tc(bp->dev, bp->max_cos);

+	/* Add all NAPI objects */
+	bnx2x_add_all_napi(bp);
 	bnx2x_napi_enable(bp);

 	/* set pf load just before approaching the MCP */
@@ -2408,6 +2410,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)

 		/* Disable HW interrupts, NAPI */
 		bnx2x_netif_stop(bp, 1);
+		/* Delete all NAPI objects */
+		bnx2x_del_all_napi(bp);

 		/* Release IRQs */
 		bnx2x_free_irq(bp);
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index dfa757e..21b5532 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -792,7 +792,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
 	bp->num_napi_queues = bp->num_queues;

 	/* Add NAPI objects */
-	for_each_napi_rx_queue(bp, i)
+	for_each_rx_queue(bp, i)
 		netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
 			       bnx2x_poll, BNX2X_NAPI_WEIGHT);
 }
@@ -801,7 +801,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
 {
 	int i;

-	for_each_napi_rx_queue(bp, i)
+	for_each_rx_queue(bp, i)
 		netif_napi_del(&bnx2x_fp(bp, i, napi));
 }

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index fc4e0e3..c37a68d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -2888,11 +2888,9 @@ static void bnx2x_get_channels(struct net_device *dev,
  */
 static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss)
 {
-	bnx2x_del_all_napi(bp);
 	bnx2x_disable_msi(bp);
 	BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE;
 	bnx2x_set_int_mode(bp);
-	bnx2x_add_all_napi(bp);
 }

 /**
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index dd451c3..f6d6baf 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -8441,6 +8441,8 @@ unload_error:

 	/* Disable HW interrupts, NAPI */
 	bnx2x_netif_stop(bp, 1);
+	/* Delete all NAPI objects */
+	bnx2x_del_all_napi(bp);

 	/* Release IRQs */
 	bnx2x_free_irq(bp);
@@ -11915,9 +11917,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
 	 */
 	bnx2x_set_int_mode(bp);

-	/* Add all NAPI objects */
-	bnx2x_add_all_napi(bp);
-
 	rc = register_netdev(dev);
 	if (rc) {
 		dev_err(&pdev->dev, "Cannot register net device\n");
@@ -11992,9 +11991,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)

 	unregister_netdev(dev);

-	/* Delete all NAPI objects */
-	bnx2x_del_all_napi(bp);
-
 	/* Power on: we can't let PCI layer write to us while we are in D3 */
 	bnx2x_set_power_state(bp, PCI_D0);

@@ -12041,6 +12037,8 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
 	bnx2x_tx_disable(bp);

 	bnx2x_netif_stop(bp, 0);
+	/* Delete all NAPI objects */
+	bnx2x_del_all_napi(bp);

 	del_timer_sync(&bp->timer);

--
1.7.10

^ permalink raw reply related

* [net patch 2/2] bnx2x: Correct the ndo_poll_controller call
From: Merav Sicron @ 2012-08-27 13:26 UTC (permalink / raw)
  To: davem, netdev, eilong; +Cc: Merav Sicron, Dmitry Kravkov
In-Reply-To: <1346073980-30901-1-git-send-email-meravs@broadcom.com>

This patch correct poll_bnx2x (ndo_poll_controller call) which was not
functioning well with MSI-X.

Signed-off-by: Merav Sicron <meravs@broadcom.com>
Signed-off-by: Dmitry Kravkov <dmitry@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index f6d6baf..ce03456 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -11244,10 +11244,12 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 static void poll_bnx2x(struct net_device *dev)
 {
 	struct bnx2x *bp = netdev_priv(dev);
+	int i;

-	disable_irq(bp->pdev->irq);
-	bnx2x_interrupt(bp->pdev->irq, dev);
-	enable_irq(bp->pdev->irq);
+	for_each_eth_queue(bp, i) {
+		struct bnx2x_fastpath *fp = &bp->fp[i];
+		napi_schedule(&bnx2x_fp(bp, fp->index, napi));
+	}
 }
 #endif

--
1.7.10---

^ permalink raw reply related

* Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling
From: Jesper Dangaard Brouer @ 2012-08-27 10:13 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: netfilter-devel, netdev, Julian Anastasov, Hans Schillstrom,
	Hans Schillstrom
In-Reply-To: <Pine.GSO.4.63.1208262318550.16771@stinky-local.trash.net>

On Sun, 2012-08-26 at 23:20 +0200, Patrick McHardy wrote:
> On Wed, 22 Aug 2012, Jesper Dangaard Brouer wrote:
> 
> > On Sun, 2012-08-19 at 21:44 +0200, Patrick McHardy wrote:
> >> On Sun, 19 Aug 2012, Jesper Dangaard Brouer wrote:
> >>> On Sat, 2012-08-18 at 14:26 +0200, Patrick McHardy wrote:
> > [...]
> >
> >>> Don't I need to load some of the helper modules, or just the
> >>> nf_conntrack_ipv6 module, or perhaps only nf_defrag_ipv6 ?
> >>
> >> Not with the entire patchset, just IPv6 conntrack is enough. Aith IPv6 NAT
> >> the first packet of a connection must always be defragemented, independant
> >> of an assigned helper.
> >
> > When loading "nf_conntrack_ipv6" I run into issues.
> >
> > When sending a fragmented UDP packet.  With these patches, the IPVS
> > stack will no longer see the fragmented packets, but instead see one
> > large SKB.  This will trigger a MTU path check in e.g.
> > ip_vs_dr_xmit_v6() and an ICMPv6 too big packet is send back.
> >
> >  IPVS: ip_vs_dr_xmit_v6(): frag needed
> >
> > Perhaps we could change/fix the MTU check in IPVS?
> > (This would also solve issues I've seen with TSO/GSO frames, hitting
> > this code path).
> 
> I guess this should use the same check as in IPv6 output, check
> whether IP6CB(skb)->max_frag_size is != 0 and > MTU and only send
> an ICMPv6 error in that case.

Hans have (already) proposed this solution:

  if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) ||
      (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) {

And I have tested it works.
But I'm not sure about, if we really need the "!skb->local_df" check ?


Thus, we should extend you patchset with a patch, that also address the
MTU checks in IPVS.

-- 
Best regards,
  Jesper Dangaard Brouer
  MSc.CS, Sr. Network Kernel Developer at Red Hat
  Author of http://www.iptv-analyzer.org
  LinkedIn: http://www.linkedin.com/in/brouer



^ permalink raw reply

* Re: [RFC PATCH] net: Add support for virtual machine device queues (VMDQ)
From: Or Gerlitz @ 2012-08-27  9:47 UTC (permalink / raw)
  To: John Fastabend; +Cc: davem, roland, netdev, ali, sean.hefty, shlomop
In-Reply-To: <503A7462.1030803@intel.com>

On Sun, Aug 26, 2012 at 10:09 PM, John Fastabend
<john.r.fastabend@intel.com> wrote:
> That seems reasonable to me. Adding a 'sub' argument to the set
> routines should do it. Also the 'get' routines would need to be
> extended to report back these virtual net devices.
>
> int (*ndo_set_vf_mac)(struct net_device *dev, int vf, int sub, u8* mac);
> int (*ndo_set_vf_vlan)(struct net_device *dev,
>                        int vf, int sub, u16 vlan, u8 qos);
> int (*ndo_set_vf_tx_rate)(struct net_device *dev,
>                           int vf, int sub, int rate);
> int (*ndo_set_vf_spoofchk)(struct net_device *dev,
>                            int vf, int sub, bool setting);
> int (*ndo_get_vf_config)(struct net_device *dev,
>                          int vf, int sub,
>                          struct fila_vf_info *ivf)

> I would need to check if any of the ixgbe/igb supported hardware can
> support virtual device queues on virtual functions like this but I
> presume if your looking at this you have some hardware that can.

Yes, we look on HW that can.

Your suggestion makes sense, I will check here if this well addresses
the eswitch
use case we envision or/what is missing.

Or.

^ permalink raw reply

* Re: [PATCH] decnet: fix shutdown parameter checking
From: Steven Whitehouse @ 2012-08-27  9:16 UTC (permalink / raw)
  To: Xi Wang; +Cc: David S. Miller, netdev, linux-kernel
In-Reply-To: <1346035027-2347-1-git-send-email-xi.wang@gmail.com>


On Sun, 2012-08-26 at 22:37 -0400, Xi Wang wrote:
> The allowed value of "how" is SHUT_RD/SHUT_WR/SHUT_RDWR (0/1/2),
> rather than SHUTDOWN_MASK (3).
> 
> Signed-off-by: Xi Wang <xi.wang@gmail.com>
Acked-by: Steven Whitehouse <swhiteho@redhat.com>

Although it could be argued that we should also continue to accept the
value 3 just in case there is any userland software out there which
sends that value,

Steve.

> ---
>  net/decnet/af_decnet.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
> index 2ba1a28..307c322 100644
> --- a/net/decnet/af_decnet.c
> +++ b/net/decnet/af_decnet.c
> @@ -1313,10 +1313,10 @@ static int dn_shutdown(struct socket *sock, int how)
>  	if (scp->state == DN_O)
>  		goto out;
>  
> -	if (how != SHUTDOWN_MASK)
> +	if (how != SHUT_RDWR)
>  		goto out;
>  
> -	sk->sk_shutdown = how;
> +	sk->sk_shutdown = SHUTDOWN_MASK;
>  	dn_destroy_sock(sk);
>  	err = 0;
>  

^ permalink raw reply

* Re: [REVIEW][PATCH 13/15] userns: Add basic quota support
From: Steven Whitehouse @ 2012-08-27  8:58 UTC (permalink / raw)
  To: Eric W. Biederman, Abhijith Das
  Cc: Alex Elder, Jan Kara, netdev, linux-kernel, David, cluster-devel,
	Ben Myers, Monakhov, linux-fsdevel, xfs, Dmitry, Miller,
	ocfs2-devel, Serge E. Hallyn
In-Reply-To: <87harqecvk.fsf@xmission.com>

Hi,

On Sat, 2012-08-25 at 17:05 -0700, Eric W. Biederman wrote:
> Two helper are added dqgetusr and dqgetgrp to allow the quota
> infrastructure to be called with a kuid and a kgid respectively.  This
> creates type safe variants of dqget and leads to shorter more
> comprehensible code.
> 
> Place the USRQUOTA and GRPQUOTA defines into enum quota_type.  This
> brings with it the ability for the compiler to check that switch
> statements handle every quota type, and the ability to mark which
> values store the type of a quota entry.
> 
> Add the data type qown_t a union of kuid_t and kgid_t. qown_t is a
> replacement for the implicit union of uid and gid stored in an
> unsigned int that is was used in the quota data structures.  Making
> the data type explicit allows the kuid_t and kgid_t type safety to
> propogate more thoroughly through the code, revealing more places
> where uid/gid conversions need be made.
> 
> Allong with the data type qown_t comes the helper functions
> qown_eq, from_qown, from_qown_munged, qown_valid, and make_qown.
> 
> Update struct dquot dq_id to be a qown_t.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use enum quota_type and qown_t.
> 
> Make minimal changes to gfs2, ocfs2, and xfs to deal with the change
> in quota structures and signatures.  The ocfs2 changes are larger than
> most because of the extensive tracing throughout the ocfs2 quota code
> that prints out dq_id.
> 

I think this is ok from the GFS2 perspective. Abhi, does it look ok to
you?

Steve.




> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: cluster-devel@redhat.com
> Cc: Mark Fasheh <mfasheh@suse.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: ocfs2-devel@oss.oracle.com
> Cc: Ben Myers <bpm@sgi.com>
> Cc: Alex Elder <elder@kernel.org>
> Cc: xfs@oss.sgi.com
> Cc: Jan Kara <jack@suse.cz>
> Cc: Dmitry Monakhov <dmonakhov@openvz.org>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
> ---
>  fs/gfs2/quota.c          |   44 ++++++++++++++---------
>  fs/ocfs2/file.c          |    6 +--
>  fs/ocfs2/quota_global.c  |   34 +++++++++++++-----
>  fs/ocfs2/quota_local.c   |   12 +++++--
>  fs/quota/dquot.c         |   43 ++++++++++++----------
>  fs/quota/netlink.c       |   11 ++++--
>  fs/quota/quota.c         |   44 +++++++++++++++-------
>  fs/quota/quota_tree.c    |   20 +++++++---
>  fs/quota/quota_v1.c      |    8 +++--
>  fs/quota/quota_v2.c      |   14 +++++--
>  fs/xfs/xfs_quotaops.c    |   18 ++++++----
>  fs/xfs/xfs_trans_dquot.c |    8 +++--
>  include/linux/quota.h    |   91 +++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/quotaops.h |   18 +++++++--
>  init/Kconfig             |    2 -
>  15 files changed, 270 insertions(+), 103 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index a3bde91..858f052 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>                  return 0;
>  
>  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
> +		enum quota_type qtype;
> +		qown_t qown;
>  		qd = ip->i_res->rs_qa_qd[x];
>  
>  		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
> @@ -1068,10 +1070,11 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  		value += qd->qd_change;
>  		spin_unlock(&qd_lru_lock);
>  
> +		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
> +		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
>  		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
>  			print_message(qd, "exceeded");
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
>  
>  			error = -EDQUOT;
> @@ -1081,8 +1084,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  			   time_after_eq(jiffies, qd->qd_last_warn +
>  					 gfs2_tune_get(sdp,
>  						gt_quota_warn_period) * HZ)) {
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
>  			error = print_message(qd, "warning");
>  			qd->qd_last_warn = jiffies;
> @@ -1469,28 +1471,32 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  	return 0;
>  }
>  
> -static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_get_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_quota_lvb *qlvb;
>  	struct gfs2_quota_data *qd;
>  	struct gfs2_holder q_gh;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	memset(fdq, 0, sizeof(struct fs_disk_quota));
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	if (type == USRQUOTA)
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  	else if (type == GRPQUOTA)
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  	else
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  	error = do_glock(qd, FORCE, &q_gh);
> @@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
>  	fdq->d_version = FS_DQUOT_VERSION;
> -	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	fdq->d_id = id;
> +	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> +	fdq->d_id = gfs_id;
>  	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
>  	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
>  	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
> @@ -1514,8 +1520,8 @@ out:
>  /* GFS2 only supports a subset of the XFS fields */
>  #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
>  
> -static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_set_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
> @@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  	int alloc_required;
>  	loff_t offset;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	switch(type) {
>  	case USRQUOTA:
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  		if (fdq->d_flags != FS_USER_QUOTA)
>  			return -EINVAL;
>  		break;
>  	case GRPQUOTA:
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  		if (fdq->d_flags != FS_GROUP_QUOTA)
>  			return -EINVAL;
>  		break;
> @@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
>  		return -EINVAL;
> -	if (fdq->d_id != id)
> +	if (fdq->d_id != gfs_id)
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 46a1f6d..063e889 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> -			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
> -						      USRQUOTA);
> +			transfer_to[USRQUOTA] = dqgetusr(sb, attr->ia_uid);
>  			if (!transfer_to[USRQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> @@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
> -			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
> -						      GRPQUOTA);
> +			transfer_to[GRPQUOTA] = dqgetgrp(sb, attr->ia_gid);
>  			if (!transfer_to[GRPQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
> index 0a86e30..88360f1 100644
> --- a/fs/ocfs2/quota_global.c
> +++ b/fs/ocfs2/quota_global.c
> @@ -95,7 +95,8 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct mem_dqblk *m = &dquot->dq_dqb;
>  
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_type,
> +					  dquot->dq_id));
>  	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
>  	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
>  	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
> @@ -113,10 +114,13 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct ocfs2_mem_dqinfo *oinfo =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  struct qtree_fmt_operations ocfs2_global_ops = {
> @@ -504,7 +508,9 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	olditime = dquot->dq_dqb.dqb_itime;
>  	oldbtime = dquot->dq_dqb.dqb_btime;
>  	ocfs2_global_disk2memdqb(dquot, &dqblk);
> -	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
> +	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					 dquot->dq_id),
> +			       dquot->dq_dqb.dqb_curspace,
>  			       (long long)spacechange,
>  			       dquot->dq_dqb.dqb_curinodes,
>  			       (long long)inodechange);
> @@ -556,7 +562,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	if (err < 0) {
>  		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
>  			       " (type=%d, id=%u)\n", dquot->dq_type,
> -			       (unsigned)dquot->dq_id);
> +			       (unsigned)from_qown(&init_user_ns, dquot->dq_type,
> +						   dquot->dq_id));
>  		goto out;
>  	}
>  	if (freeing)
> @@ -591,7 +598,9 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	int status = 0;
>  
> -	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
> +	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_type,
> +						dquot->dq_id),
> +				      dquot->dq_type,
>  				      type, sb->s_id);
>  	if (type != dquot->dq_type)
>  		goto out;
> @@ -643,7 +652,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					   dquot->dq_id),
> +				dquot->dq_type);
>  
>  	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
>  	if (IS_ERR(handle)) {
> @@ -681,7 +692,9 @@ static int ocfs2_release_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					    dquot->dq_id),
> +				  dquot->dq_type);
>  
>  	mutex_lock(&dquot->dq_lock);
>  	/* Check whether we are not racing with some other dqget() */
> @@ -739,7 +752,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
>  	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
>  	handle_t *handle;
>  
> -	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
> +	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, type, dquot->dq_id),
> +				  type);
>  	mutex_lock(&dquot->dq_lock);
>  	/*
>  	 * We need an exclusive lock, because we're going to update use count
> @@ -826,7 +840,9 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
>  	handle_t *handle;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
> +	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, type,
> +					       dquot->dq_id),
> +				     type);
>  
>  	/* In case user set some limits, sync dquot immediately to global
>  	 * quota file so that information propagates quicker */
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index f100bf7..a80936e 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -501,7 +501,10 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
>  			}
>  			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
>  				ol_dqblk_block_off(sb, chunk, bit));
> -			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
> +			dquot = dqget(sb,
> +				      make_qown(&init_user_ns, type,
> +						le64_to_cpu(dqblk->dqb_id)),
> +				      type);
>  			if (!dquot) {
>  				status = -EIO;
>  				mlog(ML_ERROR, "Failed to get quota structure "
> @@ -881,7 +884,9 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
>  		+ ol_dqblk_block_offset(sb, od->dq_local_off));
>  
> -	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
> +	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
> +					      od->dq_dquot.dq_type,
> +					      od->dq_dquot.dq_id));
>  	spin_lock(&dq_data_lock);
>  	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
>  					  od->dq_origspace);
> @@ -891,7 +896,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	trace_olq_set_dquot(
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
> -		od->dq_dquot.dq_id);
> +		from_qown(&init_user_ns, od->dq_dquot.dq_type,
> +			  od->dq_dquot.dq_id));
>  }
>  
>  /* Write dquot to local quota file */
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 36a29b7..5fbd1d9a 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -253,10 +253,12 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
>  static void __dquot_initialize(struct inode *inode, int type);
>  
>  static inline unsigned int
> -hashfn(const struct super_block *sb, unsigned int id, int type)
> +hashfn(const struct super_block *sb, qown_t qown, enum quota_type type)
>  {
> +	unsigned int id;
>  	unsigned long tmp;
>  
> +	id = from_qown(&init_user_ns, type, qown);
>  	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
>  	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
>  }
> @@ -277,15 +279,15 @@ static inline void remove_dquot_hash(struct dquot *dquot)
>  }
>  
>  static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
> -				unsigned int id, int type)
> +				qown_t id, enum quota_type type)
>  {
>  	struct hlist_node *node;
>  	struct dquot *dquot;
>  
>  	hlist_for_each (node, dquot_hash+hashent) {
>  		dquot = hlist_entry(node, struct dquot, dq_hash);
> -		if (dquot->dq_sb == sb && dquot->dq_id == id &&
> -		    dquot->dq_type == type)
> +		if (dquot->dq_sb == sb && dquot->dq_type == type &&
> +		    qown_eq(dquot->dq_id, id, type))
>  			return dquot;
>  	}
>  	return NULL;
> @@ -741,7 +743,9 @@ void dqput(struct dquot *dquot)
>  #ifdef CONFIG_QUOTA_DEBUG
>  	if (!atomic_read(&dquot->dq_count)) {
>  		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
> -			    quotatypes[dquot->dq_type], dquot->dq_id);
> +			    quotatypes[dquot->dq_type],
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		BUG();
>  	}
>  #endif
> @@ -829,7 +833,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
>   *   a) checking for quota flags under dq_list_lock and
>   *   b) getting a reference to dquot before we release dq_list_lock
>   */
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type)
>  {
>  	unsigned int hashent = hashfn(sb, id, type);
>  	struct dquot *dquot = NULL, *empty = NULL;
> @@ -1129,7 +1133,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
>  
>  struct dquot_warn {
>  	struct super_block *w_sb;
> -	qid_t w_dq_id;
> +	qown_t w_dq_id;
>  	short w_dq_type;
>  	short w_type;
>  };
> @@ -1156,9 +1160,9 @@ static int need_print_warning(struct dquot_warn *warn)
>  
>  	switch (warn->w_dq_type) {
>  		case USRQUOTA:
> -			return current_fsuid() == warn->w_dq_id;
> +			return uid_eq(current_fsuid(), warn->w_dq_id.uid);
>  		case GRPQUOTA:
> -			return in_group_p(warn->w_dq_id);
> +			return in_group_p(warn->w_dq_id.gid);
>  	}
>  	return 0;
>  }
> @@ -1390,7 +1394,6 @@ static int dquot_active(const struct inode *inode)
>   */
>  static void __dquot_initialize(struct inode *inode, int type)
>  {
> -	unsigned int id = 0;
>  	int cnt;
>  	struct dquot *got[MAXQUOTAS];
>  	struct super_block *sb = inode->i_sb;
> @@ -1403,15 +1406,16 @@ static void __dquot_initialize(struct inode *inode, int type)
>  
>  	/* First get references to structures we might need. */
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> +		qown_t id;
>  		got[cnt] = NULL;
>  		if (type != -1 && cnt != type)
>  			continue;
>  		switch (cnt) {
>  		case USRQUOTA:
> -			id = inode->i_uid;
> +			id.uid = inode->i_uid;
>  			break;
>  		case GRPQUOTA:
> -			id = inode->i_gid;
> +			id.gid = inode->i_gid;
>  			break;
>  		}
>  		got[cnt] = dqget(sb, id, cnt);
> @@ -1897,10 +1901,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
>  	if (!dquot_active(inode))
>  		return 0;
>  
> -	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
> -		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
> -	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
> -		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
> +	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
> +		transfer_to[USRQUOTA] = dqgetusr(sb, iattr->ia_uid);
> +	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
> +		transfer_to[GRPQUOTA] = dqgetgrp(sb, iattr->ia_gid);
>  
>  	ret = __dquot_transfer(inode, transfer_to);
>  	dqput_all(transfer_to);
> @@ -2362,7 +2366,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	di->d_version = FS_DQUOT_VERSION;
>  	di->d_flags = dquot->dq_type == USRQUOTA ?
>  			FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	di->d_id = dquot->dq_id;
> +	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_type,
> +				    dquot->dq_id);
>  
>  	spin_lock(&dq_data_lock);
>  	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
> @@ -2376,7 +2381,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	spin_unlock(&dq_data_lock);
>  }
>  
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		    struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> @@ -2488,7 +2493,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	return 0;
>  }
>  
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		  struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
> index d67908b..b2678da 100644
> --- a/fs/quota/netlink.c
> +++ b/fs/quota/netlink.c
> @@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
>   *
>   */
>  
> -void quota_send_warning(short type, unsigned int id, dev_t dev,
> +void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			const char warntype)
>  {
>  	static atomic_t seq;
> @@ -59,7 +59,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
> +	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
> +			  from_qown_munged(&init_user_ns, type, id));
>  	if (ret)
>  		goto attr_err_out;
>  	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
> @@ -71,7 +72,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
> +	/* Report the current user as seen by the filesystem that issues
> +	 * quota warning.
> +	 */
> +	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
> +			  from_kuid_munged(&init_user_ns, current_uid()));
>  	if (ret)
>  		goto attr_err_out;
>  	genlmsg_end(skb, msg_head);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 6f15578..b9f44b7 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
>  	/* allow to query information for dquots we "own" */
>  	case Q_GETQUOTA:
>  	case Q_XGETQUOTA:
> -		if ((type == USRQUOTA && current_euid() == id) ||
> -		    (type == GRPQUOTA && in_egroup_p(id)))
> +		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> +		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
>  			break;
>  		/*FALLTHROUGH*/
>  	default:
> @@ -62,7 +62,7 @@ static int quota_sync_all(int type)
>  	return ret;
>  }
>  
> -static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
> +static int quota_quotaon(struct super_block *sb, enum quota_type type, int cmd, qid_t id,
>  		         struct path *path)
>  {
>  	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
> @@ -127,16 +127,20 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>  	dst->dqb_valid = QIF_ALL;
>  }
>  
> -static int quota_getquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_getquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id, void __user *addr)
>  {
> +	qown_t qown;
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (ret)
>  		return ret;
>  	copy_to_if_dqblk(&idq, &fdq);
> @@ -171,18 +175,22 @@ static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
>  		dst->d_fieldmask |= FS_DQ_ITIMER;
>  }
>  
> -static int quota_setquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_setquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id,  void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&idq, addr, sizeof(idq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
>  	copy_from_if_dqblk(&fdq, &idq);
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
>  static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
> @@ -209,27 +217,35 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
>  	return ret;
>  }
>  
> -static int quota_setxquota(struct super_block *sb, int type, qid_t id,
> +static int quota_setxquota(struct super_block *sb, enum quota_type type, qid_t id,
>  			   void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&fdq, addr, sizeof(fdq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
> -static int quota_getxquota(struct super_block *sb, int type, qid_t id,
> -			   void __user *addr)
> +static int quota_getxquota(struct super_block *sb, enum quota_type type,
> +			   qid_t id, void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
>  		return -EFAULT;
>  	return ret;
> diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
> index e41c1becf..4704619 100644
> --- a/fs/quota/quota_tree.c
> +++ b/fs/quota/quota_tree.c
> @@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
>  
>  #define __QUOTA_QT_PARANOIA
>  
> -static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
> +static int get_index(struct qtree_mem_dqinfo *info, qown_t qown, int depth)
>  {
>  	unsigned int epb = info->dqi_usable_bs >> 2;
> +	qid_t id;
>  
> +	id = from_qown(&init_user_ns, info->dqi_type, qown);
>  	depth = info->dqi_qtree_depth - depth - 1;
>  	while (depth--)
>  		id /= epb;
> @@ -538,8 +540,10 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
>  		ddquot += info->dqi_entry_size;
>  	}
>  	if (i == qtree_dqstr_in_blk(info)) {
> -		quota_error(dquot->dq_sb, "Quota for id %u referenced "
> -			    "but not present", dquot->dq_id);
> +		quota_error(dquot->dq_sb,
> +			    "Quota for id %u referenced but not present",
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		ret = -EIO;
>  		goto out_buf;
>  	} else {
> @@ -607,8 +611,11 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		offset = find_dqentry(info, dquot);
>  		if (offset <= 0) {	/* Entry not present? */
>  			if (offset < 0)
> -				quota_error(sb, "Can't read quota structure "
> -					    "for id %u", dquot->dq_id);
> +				quota_error(sb,"Can't read quota structure "
> +					    "for id %u",
> +					    from_qown(&init_user_ns,
> +						      dquot->dq_type,
> +						      dquot->dq_id));
>  			dquot->dq_off = 0;
>  			set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
> @@ -626,7 +633,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		if (ret >= 0)
>  			ret = -EIO;
>  		quota_error(sb, "Error while reading quota structure for id %u",
> -			    dquot->dq_id);
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
>  		kfree(ddquot);
> diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
> index 34b37a6..7c028f9 100644
> --- a/fs/quota/quota_v1.c
> +++ b/fs/quota/quota_v1.c
> @@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
>  	/* Set structure to 0s in case read fails/is after end of file */
>  	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
>  	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
> -			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
> +			sizeof(struct v1_disk_dqblk),
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  
>  	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
>  	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
> @@ -83,7 +84,8 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	struct v1_disk_dqblk dqblk;
>  
>  	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
> -	if (dquot->dq_id == 0) {
> +	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
> +	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
>  		dqblk.dqb_btime =
>  			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
>  		dqblk.dqb_itime =
> @@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	if (sb_dqopt(dquot->dq_sb)->files[type])
>  		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
>  			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
> -			v1_dqoff(dquot->dq_id));
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  	if (ret != sizeof(struct v1_disk_dqblk)) {
>  		quota_error(dquot->dq_sb, "dquota write failed");
>  		if (ret >= 0)
> diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
> index f1ab360..b9068b7 100644
> --- a/fs/quota/quota_v2.c
> +++ b/fs/quota/quota_v2.c
> @@ -206,7 +206,8 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -216,10 +217,12 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
>  	struct v2r0_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
> @@ -257,7 +260,8 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -267,10 +271,12 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
>  	struct v2r1_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static int v2_read_dquot(struct dquot *dquot)
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index fed504f..9ee2d6d 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -29,7 +29,7 @@
>  
> 
>  STATIC int
> -xfs_quota_type(int type)
> +xfs_quota_type(enum quota_type type)
>  {
>  	switch (type) {
>  	case USRQUOTA:
> @@ -97,28 +97,31 @@ xfs_fs_set_xstate(
>  STATIC int
>  xfs_fs_get_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>  		return -ENOSYS;
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  STATIC int
>  xfs_fs_set_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (sb->s_flags & MS_RDONLY)
>  		return -EROFS;
> @@ -127,7 +130,8 @@ xfs_fs_set_dqblk(
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  const struct quotactl_ops xfs_quotactl_operations = {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index bcb6054..0c7ab32 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -575,12 +575,14 @@ xfs_quota_warn(
>  	struct xfs_dquot	*dqp,
>  	int			type)
>  {
> +	enum quota_type qtype;
> +	qown_t qown;
>  	/* no warnings for project quotas - we just return ENOSPC later */
>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>  		return;
> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
> -			   type);
> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
> +	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
> +	quota_send_warning(qtype, qown, mp->m_super->s_dev, type);
>  }
>  
>  /*
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 524ede8..67921d5 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -181,10 +181,91 @@ enum {
>  #include <linux/dqblk_v2.h>
>  
>  #include <linux/atomic.h>
> +#include <linux/uidgid.h>
>  
>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>  typedef long long qsize_t;	/* Type in which we store sizes */
>  
> +#undef USRQUOTA
> +#undef GRPQUOTA
> +enum quota_type {
> +	USRQUOTA = 0,
> +	GRPQUOTA = 1,
> +};
> +
> +typedef union quota_id {
> +	kuid_t uid;
> +	kgid_t gid;
> +} qown_t;			/* Type in which we store the quota owner */
> +
> +static inline bool qown_eq(qown_t left, qown_t right, enum quota_type type)
> +{
> +	switch(type) {
> +	case USRQUOTA:
> +		return uid_eq(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_eq(left.gid, right.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown(struct user_namespace *user_ns,
> +			    enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown_munged(struct user_namespace *user_ns,
> +				   enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid_munged(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid_munged(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline qown_t make_qown(struct user_namespace *user_ns,
> +			      enum quota_type type, qid_t id)
> +{
> +	qown_t qown;
> +
> +	switch (type) {
> +	case USRQUOTA:
> +		qown.uid = make_kuid(user_ns, id);
> +		break;
> +	case GRPQUOTA:
> +		qown.gid = make_kgid(user_ns, id);
> +		break;
> +	default:
> +		BUG();
> +	}
> +	return qown;
> +}
> +
> +static inline bool qown_valid(enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return uid_valid(qown.uid);
> +	case GRPQUOTA:
> +		return gid_valid(qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
>  extern spinlock_t dq_data_lock;
>  
>  /* Maximal numbers of writes for quota operation (insert/delete/update)
> @@ -294,7 +375,7 @@ struct dquot {
>  	atomic_t dq_count;		/* Use count */
>  	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
>  	struct super_block *dq_sb;	/* superblock this applies to */
> -	unsigned int dq_id;		/* ID this applies to (uid, gid) */
> +	qown_t dq_id;			/* ID this applies to (uid, gid) */
>  	loff_t dq_off;			/* Offset of dquot on disk */
>  	unsigned long dq_flags;		/* See DQ_* */
>  	short dq_type;			/* Type of quota */
> @@ -336,8 +417,8 @@ struct quotactl_ops {
>  	int (*quota_sync)(struct super_block *, int);
>  	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
>  	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
> -	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> -	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> +	int (*get_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
> +	int (*set_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
>  	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
>  	int (*set_xstate)(struct super_block *, unsigned int, int);
>  };
> @@ -386,10 +467,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
>  }
>  
>  #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
> -extern void quota_send_warning(short type, unsigned int id, dev_t dev,
> +extern void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			       const char warntype);
>  #else
> -static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
> +static inline void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  				      const char warntype)
>  {
>  	return;
> diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
> index ec6b65f..d988b11 100644
> --- a/include/linux/quotaops.h
> +++ b/include/linux/quotaops.h
> @@ -44,13 +44,23 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
>  
>  void dquot_initialize(struct inode *inode);
>  void dquot_drop(struct inode *inode);
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type);
>  void dqput(struct dquot *dquot);
>  int dquot_scan_active(struct super_block *sb,
>  		      int (*fn)(struct dquot *dquot, unsigned long priv),
>  		      unsigned long priv);
>  struct dquot *dquot_alloc(struct super_block *sb, int type);
>  void dquot_destroy(struct dquot *dquot);
> +static inline struct dquot *dqgetusr(struct super_block *sb, kuid_t uid)
> +{
> +	qown_t id = { .uid = uid };
> +	return dqget(sb, id, USRQUOTA);
> +}
> +static inline struct dquot *dqgetgrp(struct super_block *sb, kgid_t gid)
> +{
> +	qown_t id = { .gid = gid };
> +	return dqget(sb, id, GRPQUOTA);
> +}
>  
>  int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
>  void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
> @@ -87,15 +97,15 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
>  int dquot_quota_sync(struct super_block *sb, int type);
>  int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
>  int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
>  
>  int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
>  int dquot_transfer(struct inode *inode, struct iattr *iattr);
>  
> -static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
> +static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, enum quota_type type)
>  {
>  	return sb_dqopt(sb)->info + type;
>  }
> diff --git a/init/Kconfig b/init/Kconfig
> index 2a388e5..a0bccce 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -928,8 +928,6 @@ config UIDGID_CONVERTED
>  	depends on IMA = n
>  	depends on EVM = n
>  	depends on FS_POSIX_ACL = n
> -	depends on QUOTA = n
> -	depends on QUOTACTL = n
>  
>  	# Networking
>  	depends on NET_9P = n

^ permalink raw reply

* Re: [REVIEW][PATCH 13/15] userns: Add basic quota support
From: Jan Kara @ 2012-08-27  8:50 UTC (permalink / raw)
  To: Eric W. Biederman
  Cc: linux-kernel, netdev, linux-fsdevel, Serge E. Hallyn,
	David Miller, Steven Whitehouse, cluster-devel, Mark Fasheh,
	Joel Becker, ocfs2-devel, Ben Myers, Alex Elder, xfs, Jan Kara,
	Dmitry Monakhov
In-Reply-To: <87harqecvk.fsf@xmission.com>

  Hello,

On Sat 25-08-12 17:05:35, Eric W. Biederman wrote:
> Two helper are added dqgetusr and dqgetgrp to allow the quota
> infrastructure to be called with a kuid and a kgid respectively.  This
> creates type safe variants of dqget and leads to shorter more
> comprehensible code.
  It would look more comprehensible to me to have functions like:
kuid2qown() and kgid2qown() and then call dqget(sb, kuid2qown(attr->uid))
(see below for qown_t change proposal). The code then at the first look
explains what is going on... Hmm?

> Place the USRQUOTA and GRPQUOTA defines into enum quota_type.  This
> brings with it the ability for the compiler to check that switch
> statements handle every quota type, and the ability to mark which
> values store the type of a quota entry.
  OK, makes sense.

> Add the data type qown_t a union of kuid_t and kgid_t. qown_t is a
> replacement for the implicit union of uid and gid stored in an
> unsigned int that is was used in the quota data structures.  Making
> the data type explicit allows the kuid_t and kgid_t type safety to
> propogate more thoroughly through the code, revealing more places
> where uid/gid conversions need be made.
  Hum, when we already do this, wouldn't it make more sense to embed quota
type in qown_t? Because with the union thing you have no meaningful way of
accessing that type without having quota type anyway. So having that in a
single structure makes a lot of sense, plus it makes prototypes shorter...
And you have to call make_qown() anyway...

> Allong with the data type qown_t comes the helper functions
> qown_eq, from_qown, from_qown_munged, qown_valid, and make_qown.
> 
> Update struct dquot dq_id to be a qown_t.
> 
> Update the signature of dqget, quota_send_warning, dquot_get_dqblk,
> and dquot_set_dqblk to use enum quota_type and qown_t.
> 
> Make minimal changes to gfs2, ocfs2, and xfs to deal with the change
> in quota structures and signatures.  The ocfs2 changes are larger than
> most because of the extensive tracing throughout the ocfs2 quota code
> that prints out dq_id.
  Otherwise the changes look OK to me, although I didn't check them in
detail yet (as above suggestions will change the code anyway).

								Honza
> 
> Cc: Steven Whitehouse <swhiteho@redhat.com>
> Cc: cluster-devel@redhat.com
> Cc: Mark Fasheh <mfasheh@suse.com>
> Cc: Joel Becker <jlbec@evilplan.org>
> Cc: ocfs2-devel@oss.oracle.com
> Cc: Ben Myers <bpm@sgi.com>
> Cc: Alex Elder <elder@kernel.org>
> Cc: xfs@oss.sgi.com
> Cc: Jan Kara <jack@suse.cz>
> Cc: Dmitry Monakhov <dmonakhov@openvz.org>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
> ---
>  fs/gfs2/quota.c          |   44 ++++++++++++++---------
>  fs/ocfs2/file.c          |    6 +--
>  fs/ocfs2/quota_global.c  |   34 +++++++++++++-----
>  fs/ocfs2/quota_local.c   |   12 +++++--
>  fs/quota/dquot.c         |   43 ++++++++++++----------
>  fs/quota/netlink.c       |   11 ++++--
>  fs/quota/quota.c         |   44 +++++++++++++++-------
>  fs/quota/quota_tree.c    |   20 +++++++---
>  fs/quota/quota_v1.c      |    8 +++--
>  fs/quota/quota_v2.c      |   14 +++++--
>  fs/xfs/xfs_quotaops.c    |   18 ++++++----
>  fs/xfs/xfs_trans_dquot.c |    8 +++--
>  include/linux/quota.h    |   91 +++++++++++++++++++++++++++++++++++++++++++---
>  include/linux/quotaops.h |   18 +++++++--
>  init/Kconfig             |    2 -
>  15 files changed, 270 insertions(+), 103 deletions(-)
> 
> diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
> index a3bde91..858f052 100644
> --- a/fs/gfs2/quota.c
> +++ b/fs/gfs2/quota.c
> @@ -1057,6 +1057,8 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>                  return 0;
>  
>  	for (x = 0; x < ip->i_res->rs_qa_qd_num; x++) {
> +		enum quota_type qtype;
> +		qown_t qown;
>  		qd = ip->i_res->rs_qa_qd[x];
>  
>  		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
> @@ -1068,10 +1070,11 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  		value += qd->qd_change;
>  		spin_unlock(&qd_lru_lock);
>  
> +		qtype = test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA;
> +		qown = make_qown(&init_user_ns, qtype, qd->qd_id);
>  		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
>  			print_message(qd, "exceeded");
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN);
>  
>  			error = -EDQUOT;
> @@ -1081,8 +1084,7 @@ int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
>  			   time_after_eq(jiffies, qd->qd_last_warn +
>  					 gfs2_tune_get(sdp,
>  						gt_quota_warn_period) * HZ)) {
> -			quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ?
> -					   USRQUOTA : GRPQUOTA, qd->qd_id,
> +			quota_send_warning(qtype, qown,
>  					   sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN);
>  			error = print_message(qd, "warning");
>  			qd->qd_last_warn = jiffies;
> @@ -1469,28 +1471,32 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
>  	return 0;
>  }
>  
> -static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_get_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_quota_lvb *qlvb;
>  	struct gfs2_quota_data *qd;
>  	struct gfs2_holder q_gh;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	memset(fdq, 0, sizeof(struct fs_disk_quota));
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	if (type == USRQUOTA)
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  	else if (type == GRPQUOTA)
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  	else
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  	error = do_glock(qd, FORCE, &q_gh);
> @@ -1499,8 +1505,8 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
>  	fdq->d_version = FS_DQUOT_VERSION;
> -	fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	fdq->d_id = id;
> +	fdq->d_flags = (user == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
> +	fdq->d_id = gfs_id;
>  	fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
>  	fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
>  	fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
> @@ -1514,8 +1520,8 @@ out:
>  /* GFS2 only supports a subset of the XFS fields */
>  #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
>  
> -static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
> -			  struct fs_disk_quota *fdq)
> +static int gfs2_set_dqblk(struct super_block *sb, enum quota_type type,
> +			  qown_t id, struct fs_disk_quota *fdq)
>  {
>  	struct gfs2_sbd *sdp = sb->s_fs_info;
>  	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
> @@ -1526,18 +1532,22 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  	int alloc_required;
>  	loff_t offset;
>  	int error;
> +	int user;
> +	u32 gfs_id;
>  
>  	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
>  		return -ESRCH; /* Crazy XFS error code */
>  
> +	gfs_id = from_qown(&init_user_ns, type, id);
> +
>  	switch(type) {
>  	case USRQUOTA:
> -		type = QUOTA_USER;
> +		user = QUOTA_USER;
>  		if (fdq->d_flags != FS_USER_QUOTA)
>  			return -EINVAL;
>  		break;
>  	case GRPQUOTA:
> -		type = QUOTA_GROUP;
> +		user = QUOTA_GROUP;
>  		if (fdq->d_flags != FS_GROUP_QUOTA)
>  			return -EINVAL;
>  		break;
> @@ -1547,10 +1557,10 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
>  
>  	if (fdq->d_fieldmask & ~GFS2_FIELDMASK)
>  		return -EINVAL;
> -	if (fdq->d_id != id)
> +	if (fdq->d_id != gfs_id)
>  		return -EINVAL;
>  
> -	error = qd_get(sdp, type, id, &qd);
> +	error = qd_get(sdp, user, gfs_id, &qd);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
> index 46a1f6d..063e889 100644
> --- a/fs/ocfs2/file.c
> +++ b/fs/ocfs2/file.c
> @@ -1184,8 +1184,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
> -			transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
> -						      USRQUOTA);
> +			transfer_to[USRQUOTA] = dqgetusr(sb, attr->ia_uid);
>  			if (!transfer_to[USRQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> @@ -1194,8 +1193,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
>  		if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
>  		    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
>  		    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
> -			transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
> -						      GRPQUOTA);
> +			transfer_to[GRPQUOTA] = dqgetgrp(sb, attr->ia_gid);
>  			if (!transfer_to[GRPQUOTA]) {
>  				status = -ESRCH;
>  				goto bail_unlock;
> diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c
> index 0a86e30..88360f1 100644
> --- a/fs/ocfs2/quota_global.c
> +++ b/fs/ocfs2/quota_global.c
> @@ -95,7 +95,8 @@ static void ocfs2_global_mem2diskdqb(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct mem_dqblk *m = &dquot->dq_dqb;
>  
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns, dquot->dq_type,
> +					  dquot->dq_id));
>  	d->dqb_use_count = cpu_to_le32(OCFS2_DQUOT(dquot)->dq_use_count);
>  	d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
>  	d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
> @@ -113,10 +114,13 @@ static int ocfs2_global_is_id(void *dp, struct dquot *dquot)
>  	struct ocfs2_global_disk_dqblk *d = dp;
>  	struct ocfs2_mem_dqinfo *oinfo =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(&oinfo->dqi_gi, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  struct qtree_fmt_operations ocfs2_global_ops = {
> @@ -504,7 +508,9 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	olditime = dquot->dq_dqb.dqb_itime;
>  	oldbtime = dquot->dq_dqb.dqb_btime;
>  	ocfs2_global_disk2memdqb(dquot, &dqblk);
> -	trace_ocfs2_sync_dquot(dquot->dq_id, dquot->dq_dqb.dqb_curspace,
> +	trace_ocfs2_sync_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					 dquot->dq_id),
> +			       dquot->dq_dqb.dqb_curspace,
>  			       (long long)spacechange,
>  			       dquot->dq_dqb.dqb_curinodes,
>  			       (long long)inodechange);
> @@ -556,7 +562,8 @@ int __ocfs2_sync_dquot(struct dquot *dquot, int freeing)
>  	if (err < 0) {
>  		mlog(ML_ERROR, "Failed to lock quota info, losing quota write"
>  			       " (type=%d, id=%u)\n", dquot->dq_type,
> -			       (unsigned)dquot->dq_id);
> +			       (unsigned)from_qown(&init_user_ns, dquot->dq_type,
> +						   dquot->dq_id));
>  		goto out;
>  	}
>  	if (freeing)
> @@ -591,7 +598,9 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  	int status = 0;
>  
> -	trace_ocfs2_sync_dquot_helper(dquot->dq_id, dquot->dq_type,
> +	trace_ocfs2_sync_dquot_helper(from_qown(&init_user_ns, dquot->dq_type,
> +						dquot->dq_id),
> +				      dquot->dq_type,
>  				      type, sb->s_id);
>  	if (type != dquot->dq_type)
>  		goto out;
> @@ -643,7 +652,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_write_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_write_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					   dquot->dq_id),
> +				dquot->dq_type);
>  
>  	handle = ocfs2_start_trans(osb, OCFS2_QWRITE_CREDITS);
>  	if (IS_ERR(handle)) {
> @@ -681,7 +692,9 @@ static int ocfs2_release_dquot(struct dquot *dquot)
>  	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
>  	int status = 0;
>  
> -	trace_ocfs2_release_dquot(dquot->dq_id, dquot->dq_type);
> +	trace_ocfs2_release_dquot(from_qown(&init_user_ns, dquot->dq_type,
> +					    dquot->dq_id),
> +				  dquot->dq_type);
>  
>  	mutex_lock(&dquot->dq_lock);
>  	/* Check whether we are not racing with some other dqget() */
> @@ -739,7 +752,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
>  	int need_alloc = ocfs2_global_qinit_alloc(sb, type);
>  	handle_t *handle;
>  
> -	trace_ocfs2_acquire_dquot(dquot->dq_id, type);
> +	trace_ocfs2_acquire_dquot(from_qown(&init_user_ns, type, dquot->dq_id),
> +				  type);
>  	mutex_lock(&dquot->dq_lock);
>  	/*
>  	 * We need an exclusive lock, because we're going to update use count
> @@ -826,7 +840,9 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
>  	handle_t *handle;
>  	struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -	trace_ocfs2_mark_dquot_dirty(dquot->dq_id, type);
> +	trace_ocfs2_mark_dquot_dirty(from_qown(&init_user_ns, type,
> +					       dquot->dq_id),
> +				     type);
>  
>  	/* In case user set some limits, sync dquot immediately to global
>  	 * quota file so that information propagates quicker */
> diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c
> index f100bf7..a80936e 100644
> --- a/fs/ocfs2/quota_local.c
> +++ b/fs/ocfs2/quota_local.c
> @@ -501,7 +501,10 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
>  			}
>  			dqblk = (struct ocfs2_local_disk_dqblk *)(qbh->b_data +
>  				ol_dqblk_block_off(sb, chunk, bit));
> -			dquot = dqget(sb, le64_to_cpu(dqblk->dqb_id), type);
> +			dquot = dqget(sb,
> +				      make_qown(&init_user_ns, type,
> +						le64_to_cpu(dqblk->dqb_id)),
> +				      type);
>  			if (!dquot) {
>  				status = -EIO;
>  				mlog(ML_ERROR, "Failed to get quota structure "
> @@ -881,7 +884,9 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	dqblk = (struct ocfs2_local_disk_dqblk *)(bh->b_data
>  		+ ol_dqblk_block_offset(sb, od->dq_local_off));
>  
> -	dqblk->dqb_id = cpu_to_le64(od->dq_dquot.dq_id);
> +	dqblk->dqb_id = cpu_to_le64(from_qown(&init_user_ns,
> +					      od->dq_dquot.dq_type,
> +					      od->dq_dquot.dq_id));
>  	spin_lock(&dq_data_lock);
>  	dqblk->dqb_spacemod = cpu_to_le64(od->dq_dquot.dq_dqb.dqb_curspace -
>  					  od->dq_origspace);
> @@ -891,7 +896,8 @@ static void olq_set_dquot(struct buffer_head *bh, void *private)
>  	trace_olq_set_dquot(
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_spacemod),
>  		(unsigned long long)le64_to_cpu(dqblk->dqb_inodemod),
> -		od->dq_dquot.dq_id);
> +		from_qown(&init_user_ns, od->dq_dquot.dq_type,
> +			  od->dq_dquot.dq_id));
>  }
>  
>  /* Write dquot to local quota file */
> diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
> index 36a29b7..5fbd1d9a 100644
> --- a/fs/quota/dquot.c
> +++ b/fs/quota/dquot.c
> @@ -253,10 +253,12 @@ static qsize_t inode_get_rsv_space(struct inode *inode);
>  static void __dquot_initialize(struct inode *inode, int type);
>  
>  static inline unsigned int
> -hashfn(const struct super_block *sb, unsigned int id, int type)
> +hashfn(const struct super_block *sb, qown_t qown, enum quota_type type)
>  {
> +	unsigned int id;
>  	unsigned long tmp;
>  
> +	id = from_qown(&init_user_ns, type, qown);
>  	tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type);
>  	return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask;
>  }
> @@ -277,15 +279,15 @@ static inline void remove_dquot_hash(struct dquot *dquot)
>  }
>  
>  static struct dquot *find_dquot(unsigned int hashent, struct super_block *sb,
> -				unsigned int id, int type)
> +				qown_t id, enum quota_type type)
>  {
>  	struct hlist_node *node;
>  	struct dquot *dquot;
>  
>  	hlist_for_each (node, dquot_hash+hashent) {
>  		dquot = hlist_entry(node, struct dquot, dq_hash);
> -		if (dquot->dq_sb == sb && dquot->dq_id == id &&
> -		    dquot->dq_type == type)
> +		if (dquot->dq_sb == sb && dquot->dq_type == type &&
> +		    qown_eq(dquot->dq_id, id, type))
>  			return dquot;
>  	}
>  	return NULL;
> @@ -741,7 +743,9 @@ void dqput(struct dquot *dquot)
>  #ifdef CONFIG_QUOTA_DEBUG
>  	if (!atomic_read(&dquot->dq_count)) {
>  		quota_error(dquot->dq_sb, "trying to free free dquot of %s %d",
> -			    quotatypes[dquot->dq_type], dquot->dq_id);
> +			    quotatypes[dquot->dq_type],
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		BUG();
>  	}
>  #endif
> @@ -829,7 +833,7 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type)
>   *   a) checking for quota flags under dq_list_lock and
>   *   b) getting a reference to dquot before we release dq_list_lock
>   */
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type)
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type)
>  {
>  	unsigned int hashent = hashfn(sb, id, type);
>  	struct dquot *dquot = NULL, *empty = NULL;
> @@ -1129,7 +1133,7 @@ static void dquot_decr_space(struct dquot *dquot, qsize_t number)
>  
>  struct dquot_warn {
>  	struct super_block *w_sb;
> -	qid_t w_dq_id;
> +	qown_t w_dq_id;
>  	short w_dq_type;
>  	short w_type;
>  };
> @@ -1156,9 +1160,9 @@ static int need_print_warning(struct dquot_warn *warn)
>  
>  	switch (warn->w_dq_type) {
>  		case USRQUOTA:
> -			return current_fsuid() == warn->w_dq_id;
> +			return uid_eq(current_fsuid(), warn->w_dq_id.uid);
>  		case GRPQUOTA:
> -			return in_group_p(warn->w_dq_id);
> +			return in_group_p(warn->w_dq_id.gid);
>  	}
>  	return 0;
>  }
> @@ -1390,7 +1394,6 @@ static int dquot_active(const struct inode *inode)
>   */
>  static void __dquot_initialize(struct inode *inode, int type)
>  {
> -	unsigned int id = 0;
>  	int cnt;
>  	struct dquot *got[MAXQUOTAS];
>  	struct super_block *sb = inode->i_sb;
> @@ -1403,15 +1406,16 @@ static void __dquot_initialize(struct inode *inode, int type)
>  
>  	/* First get references to structures we might need. */
>  	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
> +		qown_t id;
>  		got[cnt] = NULL;
>  		if (type != -1 && cnt != type)
>  			continue;
>  		switch (cnt) {
>  		case USRQUOTA:
> -			id = inode->i_uid;
> +			id.uid = inode->i_uid;
>  			break;
>  		case GRPQUOTA:
> -			id = inode->i_gid;
> +			id.gid = inode->i_gid;
>  			break;
>  		}
>  		got[cnt] = dqget(sb, id, cnt);
> @@ -1897,10 +1901,10 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
>  	if (!dquot_active(inode))
>  		return 0;
>  
> -	if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
> -		transfer_to[USRQUOTA] = dqget(sb, iattr->ia_uid, USRQUOTA);
> -	if (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)
> -		transfer_to[GRPQUOTA] = dqget(sb, iattr->ia_gid, GRPQUOTA);
> +	if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid))
> +		transfer_to[USRQUOTA] = dqgetusr(sb, iattr->ia_uid);
> +	if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))
> +		transfer_to[GRPQUOTA] = dqgetgrp(sb, iattr->ia_gid);
>  
>  	ret = __dquot_transfer(inode, transfer_to);
>  	dqput_all(transfer_to);
> @@ -2362,7 +2366,8 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	di->d_version = FS_DQUOT_VERSION;
>  	di->d_flags = dquot->dq_type == USRQUOTA ?
>  			FS_USER_QUOTA : FS_GROUP_QUOTA;
> -	di->d_id = dquot->dq_id;
> +	di->d_id = from_qown_munged(current_user_ns(), dquot->dq_type,
> +				    dquot->dq_id);
>  
>  	spin_lock(&dq_data_lock);
>  	di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
> @@ -2376,7 +2381,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	spin_unlock(&dq_data_lock);
>  }
>  
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		    struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> @@ -2488,7 +2493,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
>  	return 0;
>  }
>  
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		  struct fs_disk_quota *di)
>  {
>  	struct dquot *dquot;
> diff --git a/fs/quota/netlink.c b/fs/quota/netlink.c
> index d67908b..b2678da 100644
> --- a/fs/quota/netlink.c
> +++ b/fs/quota/netlink.c
> @@ -30,7 +30,7 @@ static struct genl_family quota_genl_family = {
>   *
>   */
>  
> -void quota_send_warning(short type, unsigned int id, dev_t dev,
> +void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			const char warntype)
>  {
>  	static atomic_t seq;
> @@ -59,7 +59,8 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_QTYPE, type);
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID, id);
> +	ret = nla_put_u64(skb, QUOTA_NL_A_EXCESS_ID,
> +			  from_qown_munged(&init_user_ns, type, id));
>  	if (ret)
>  		goto attr_err_out;
>  	ret = nla_put_u32(skb, QUOTA_NL_A_WARNING, warntype);
> @@ -71,7 +72,11 @@ void quota_send_warning(short type, unsigned int id, dev_t dev,
>  	ret = nla_put_u32(skb, QUOTA_NL_A_DEV_MINOR, MINOR(dev));
>  	if (ret)
>  		goto attr_err_out;
> -	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID, current_uid());
> +	/* Report the current user as seen by the filesystem that issues
> +	 * quota warning.
> +	 */
> +	ret = nla_put_u64(skb, QUOTA_NL_A_CAUSED_ID,
> +			  from_kuid_munged(&init_user_ns, current_uid()));
>  	if (ret)
>  		goto attr_err_out;
>  	genlmsg_end(skb, msg_head);
> diff --git a/fs/quota/quota.c b/fs/quota/quota.c
> index 6f15578..b9f44b7 100644
> --- a/fs/quota/quota.c
> +++ b/fs/quota/quota.c
> @@ -32,8 +32,8 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
>  	/* allow to query information for dquots we "own" */
>  	case Q_GETQUOTA:
>  	case Q_XGETQUOTA:
> -		if ((type == USRQUOTA && current_euid() == id) ||
> -		    (type == GRPQUOTA && in_egroup_p(id)))
> +		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
> +		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
>  			break;
>  		/*FALLTHROUGH*/
>  	default:
> @@ -62,7 +62,7 @@ static int quota_sync_all(int type)
>  	return ret;
>  }
>  
> -static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
> +static int quota_quotaon(struct super_block *sb, enum quota_type type, int cmd, qid_t id,
>  		         struct path *path)
>  {
>  	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta)
> @@ -127,16 +127,20 @@ static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
>  	dst->dqb_valid = QIF_ALL;
>  }
>  
> -static int quota_getquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_getquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id, void __user *addr)
>  {
> +	qown_t qown;
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (ret)
>  		return ret;
>  	copy_to_if_dqblk(&idq, &fdq);
> @@ -171,18 +175,22 @@ static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
>  		dst->d_fieldmask |= FS_DQ_ITIMER;
>  }
>  
> -static int quota_setquota(struct super_block *sb, int type, qid_t id,
> -			  void __user *addr)
> +static int quota_setquota(struct super_block *sb, enum quota_type type,
> +			  qid_t id,  void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
>  	struct if_dqblk idq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&idq, addr, sizeof(idq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
>  	copy_from_if_dqblk(&fdq, &idq);
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
>  static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
> @@ -209,27 +217,35 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
>  	return ret;
>  }
>  
> -static int quota_setxquota(struct super_block *sb, int type, qid_t id,
> +static int quota_setxquota(struct super_block *sb, enum quota_type type, qid_t id,
>  			   void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  
>  	if (copy_from_user(&fdq, addr, sizeof(fdq)))
>  		return -EFAULT;
>  	if (!sb->s_qcop->set_dqblk)
>  		return -ENOSYS;
> -	return sb->s_qcop->set_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	return sb->s_qcop->set_dqblk(sb, type, qown, &fdq);
>  }
>  
> -static int quota_getxquota(struct super_block *sb, int type, qid_t id,
> -			   void __user *addr)
> +static int quota_getxquota(struct super_block *sb, enum quota_type type,
> +			   qid_t id, void __user *addr)
>  {
>  	struct fs_disk_quota fdq;
> +	qown_t qown;
>  	int ret;
>  
>  	if (!sb->s_qcop->get_dqblk)
>  		return -ENOSYS;
> -	ret = sb->s_qcop->get_dqblk(sb, type, id, &fdq);
> +	qown = make_qown(current_user_ns(), type, id);
> +	if (!qown_valid(type, qown))
> +		return -EINVAL;
> +	ret = sb->s_qcop->get_dqblk(sb, type, qown, &fdq);
>  	if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
>  		return -EFAULT;
>  	return ret;
> diff --git a/fs/quota/quota_tree.c b/fs/quota/quota_tree.c
> index e41c1becf..4704619 100644
> --- a/fs/quota/quota_tree.c
> +++ b/fs/quota/quota_tree.c
> @@ -22,10 +22,12 @@ MODULE_LICENSE("GPL");
>  
>  #define __QUOTA_QT_PARANOIA
>  
> -static int get_index(struct qtree_mem_dqinfo *info, qid_t id, int depth)
> +static int get_index(struct qtree_mem_dqinfo *info, qown_t qown, int depth)
>  {
>  	unsigned int epb = info->dqi_usable_bs >> 2;
> +	qid_t id;
>  
> +	id = from_qown(&init_user_ns, info->dqi_type, qown);
>  	depth = info->dqi_qtree_depth - depth - 1;
>  	while (depth--)
>  		id /= epb;
> @@ -538,8 +540,10 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
>  		ddquot += info->dqi_entry_size;
>  	}
>  	if (i == qtree_dqstr_in_blk(info)) {
> -		quota_error(dquot->dq_sb, "Quota for id %u referenced "
> -			    "but not present", dquot->dq_id);
> +		quota_error(dquot->dq_sb,
> +			    "Quota for id %u referenced but not present",
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		ret = -EIO;
>  		goto out_buf;
>  	} else {
> @@ -607,8 +611,11 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		offset = find_dqentry(info, dquot);
>  		if (offset <= 0) {	/* Entry not present? */
>  			if (offset < 0)
> -				quota_error(sb, "Can't read quota structure "
> -					    "for id %u", dquot->dq_id);
> +				quota_error(sb,"Can't read quota structure "
> +					    "for id %u",
> +					    from_qown(&init_user_ns,
> +						      dquot->dq_type,
> +						      dquot->dq_id));
>  			dquot->dq_off = 0;
>  			set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  			memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
> @@ -626,7 +633,8 @@ int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot)
>  		if (ret >= 0)
>  			ret = -EIO;
>  		quota_error(sb, "Error while reading quota structure for id %u",
> -			    dquot->dq_id);
> +			    from_qown(&init_user_ns, dquot->dq_type,
> +				      dquot->dq_id));
>  		set_bit(DQ_FAKE_B, &dquot->dq_flags);
>  		memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
>  		kfree(ddquot);
> diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c
> index 34b37a6..7c028f9 100644
> --- a/fs/quota/quota_v1.c
> +++ b/fs/quota/quota_v1.c
> @@ -63,7 +63,8 @@ static int v1_read_dqblk(struct dquot *dquot)
>  	/* Set structure to 0s in case read fails/is after end of file */
>  	memset(&dqblk, 0, sizeof(struct v1_disk_dqblk));
>  	dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type, (char *)&dqblk,
> -			sizeof(struct v1_disk_dqblk), v1_dqoff(dquot->dq_id));
> +			sizeof(struct v1_disk_dqblk),
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  
>  	v1_disk2mem_dqblk(&dquot->dq_dqb, &dqblk);
>  	if (dquot->dq_dqb.dqb_bhardlimit == 0 &&
> @@ -83,7 +84,8 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	struct v1_disk_dqblk dqblk;
>  
>  	v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb);
> -	if (dquot->dq_id == 0) {
> +	if (((type == USRQUOTA) && uid_eq(dquot->dq_id.uid, GLOBAL_ROOT_UID)) ||
> +	    ((type == GRPQUOTA) && gid_eq(dquot->dq_id.gid, GLOBAL_ROOT_GID))) {
>  		dqblk.dqb_btime =
>  			sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace;
>  		dqblk.dqb_itime =
> @@ -93,7 +95,7 @@ static int v1_commit_dqblk(struct dquot *dquot)
>  	if (sb_dqopt(dquot->dq_sb)->files[type])
>  		ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
>  			(char *)&dqblk, sizeof(struct v1_disk_dqblk),
> -			v1_dqoff(dquot->dq_id));
> +			v1_dqoff(from_qown(&init_user_ns, type, dquot->dq_id)));
>  	if (ret != sizeof(struct v1_disk_dqblk)) {
>  		quota_error(dquot->dq_sb, "dquota write failed");
>  		if (ret >= 0)
> diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
> index f1ab360..b9068b7 100644
> --- a/fs/quota/quota_v2.c
> +++ b/fs/quota/quota_v2.c
> @@ -206,7 +206,8 @@ static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -216,10 +217,12 @@ static int v2r0_is_id(void *dp, struct dquot *dquot)
>  	struct v2r0_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
> @@ -257,7 +260,8 @@ static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
>  	d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
>  	d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
>  	d->dqb_btime = cpu_to_le64(m->dqb_btime);
> -	d->dqb_id = cpu_to_le32(dquot->dq_id);
> +	d->dqb_id = cpu_to_le32(from_qown(&init_user_ns,
> +					  dquot->dq_type, dquot->dq_id));
>  	if (qtree_entry_unused(info, dp))
>  		d->dqb_itime = cpu_to_le64(1);
>  }
> @@ -267,10 +271,12 @@ static int v2r1_is_id(void *dp, struct dquot *dquot)
>  	struct v2r1_disk_dqblk *d = dp;
>  	struct qtree_mem_dqinfo *info =
>  			sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
> +	qown_t qown;
>  
>  	if (qtree_entry_unused(info, dp))
>  		return 0;
> -	return le32_to_cpu(d->dqb_id) == dquot->dq_id;
> +	qown = make_qown(&init_user_ns, dquot->dq_type, le32_to_cpu(d->dqb_id));
> +	return qown_eq(qown, dquot->dq_id, dquot->dq_type);
>  }
>  
>  static int v2_read_dquot(struct dquot *dquot)
> diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
> index fed504f..9ee2d6d 100644
> --- a/fs/xfs/xfs_quotaops.c
> +++ b/fs/xfs/xfs_quotaops.c
> @@ -29,7 +29,7 @@
>  
>  
>  STATIC int
> -xfs_quota_type(int type)
> +xfs_quota_type(enum quota_type type)
>  {
>  	switch (type) {
>  	case USRQUOTA:
> @@ -97,28 +97,31 @@ xfs_fs_set_xstate(
>  STATIC int
>  xfs_fs_get_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (!XFS_IS_QUOTA_RUNNING(mp))
>  		return -ENOSYS;
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_getquota(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_getquota(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  STATIC int
>  xfs_fs_set_dqblk(
>  	struct super_block	*sb,
> -	int			type,
> -	qid_t			id,
> +	enum quota_type		type,
> +	qown_t			id,
>  	struct fs_disk_quota	*fdq)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_dqid_t		xfs_id;
>  
>  	if (sb->s_flags & MS_RDONLY)
>  		return -EROFS;
> @@ -127,7 +130,8 @@ xfs_fs_set_dqblk(
>  	if (!XFS_IS_QUOTA_ON(mp))
>  		return -ESRCH;
>  
> -	return -xfs_qm_scall_setqlim(mp, id, xfs_quota_type(type), fdq);
> +	xfs_id = from_qown(&init_user_ns, type, id);
> +	return -xfs_qm_scall_setqlim(mp, xfs_id, xfs_quota_type(type), fdq);
>  }
>  
>  const struct quotactl_ops xfs_quotactl_operations = {
> diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
> index bcb6054..0c7ab32 100644
> --- a/fs/xfs/xfs_trans_dquot.c
> +++ b/fs/xfs/xfs_trans_dquot.c
> @@ -575,12 +575,14 @@ xfs_quota_warn(
>  	struct xfs_dquot	*dqp,
>  	int			type)
>  {
> +	enum quota_type qtype;
> +	qown_t qown;
>  	/* no warnings for project quotas - we just return ENOSPC later */
>  	if (dqp->dq_flags & XFS_DQ_PROJ)
>  		return;
> -	quota_send_warning((dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA,
> -			   be32_to_cpu(dqp->q_core.d_id), mp->m_super->s_dev,
> -			   type);
> +	qtype = (dqp->dq_flags & XFS_DQ_USER) ? USRQUOTA : GRPQUOTA;
> +	qown = make_qown(&init_user_ns, qtype, be32_to_cpu(dqp->q_core.d_id));
> +	quota_send_warning(qtype, qown, mp->m_super->s_dev, type);
>  }
>  
>  /*
> diff --git a/include/linux/quota.h b/include/linux/quota.h
> index 524ede8..67921d5 100644
> --- a/include/linux/quota.h
> +++ b/include/linux/quota.h
> @@ -181,10 +181,91 @@ enum {
>  #include <linux/dqblk_v2.h>
>  
>  #include <linux/atomic.h>
> +#include <linux/uidgid.h>
>  
>  typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
>  typedef long long qsize_t;	/* Type in which we store sizes */
>  
> +#undef USRQUOTA
> +#undef GRPQUOTA
> +enum quota_type {
> +	USRQUOTA = 0,
> +	GRPQUOTA = 1,
> +};
> +
> +typedef union quota_id {
> +	kuid_t uid;
> +	kgid_t gid;
> +} qown_t;			/* Type in which we store the quota owner */
> +
> +static inline bool qown_eq(qown_t left, qown_t right, enum quota_type type)
> +{
> +	switch(type) {
> +	case USRQUOTA:
> +		return uid_eq(left.uid, right.uid);
> +	case GRPQUOTA:
> +		return gid_eq(left.gid, right.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown(struct user_namespace *user_ns,
> +			    enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline u32 from_qown_munged(struct user_namespace *user_ns,
> +				   enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return from_kuid_munged(user_ns, qown.uid);
> +	case GRPQUOTA:
> +		return from_kgid_munged(user_ns, qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
> +static inline qown_t make_qown(struct user_namespace *user_ns,
> +			      enum quota_type type, qid_t id)
> +{
> +	qown_t qown;
> +
> +	switch (type) {
> +	case USRQUOTA:
> +		qown.uid = make_kuid(user_ns, id);
> +		break;
> +	case GRPQUOTA:
> +		qown.gid = make_kgid(user_ns, id);
> +		break;
> +	default:
> +		BUG();
> +	}
> +	return qown;
> +}
> +
> +static inline bool qown_valid(enum quota_type type, qown_t qown)
> +{
> +	switch (type) {
> +	case USRQUOTA:
> +		return uid_valid(qown.uid);
> +	case GRPQUOTA:
> +		return gid_valid(qown.gid);
> +	default:
> +		BUG();
> +	}
> +}
> +
>  extern spinlock_t dq_data_lock;
>  
>  /* Maximal numbers of writes for quota operation (insert/delete/update)
> @@ -294,7 +375,7 @@ struct dquot {
>  	atomic_t dq_count;		/* Use count */
>  	wait_queue_head_t dq_wait_unused;	/* Wait queue for dquot to become unused */
>  	struct super_block *dq_sb;	/* superblock this applies to */
> -	unsigned int dq_id;		/* ID this applies to (uid, gid) */
> +	qown_t dq_id;			/* ID this applies to (uid, gid) */
>  	loff_t dq_off;			/* Offset of dquot on disk */
>  	unsigned long dq_flags;		/* See DQ_* */
>  	short dq_type;			/* Type of quota */
> @@ -336,8 +417,8 @@ struct quotactl_ops {
>  	int (*quota_sync)(struct super_block *, int);
>  	int (*get_info)(struct super_block *, int, struct if_dqinfo *);
>  	int (*set_info)(struct super_block *, int, struct if_dqinfo *);
> -	int (*get_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> -	int (*set_dqblk)(struct super_block *, int, qid_t, struct fs_disk_quota *);
> +	int (*get_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
> +	int (*set_dqblk)(struct super_block *, enum quota_type, qown_t, struct fs_disk_quota *);
>  	int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
>  	int (*set_xstate)(struct super_block *, unsigned int, int);
>  };
> @@ -386,10 +467,10 @@ static inline unsigned int dquot_generic_flag(unsigned int flags, int type)
>  }
>  
>  #ifdef CONFIG_QUOTA_NETLINK_INTERFACE
> -extern void quota_send_warning(short type, unsigned int id, dev_t dev,
> +extern void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  			       const char warntype);
>  #else
> -static inline void quota_send_warning(short type, unsigned int id, dev_t dev,
> +static inline void quota_send_warning(enum quota_type type, qown_t id, dev_t dev,
>  				      const char warntype)
>  {
>  	return;
> diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
> index ec6b65f..d988b11 100644
> --- a/include/linux/quotaops.h
> +++ b/include/linux/quotaops.h
> @@ -44,13 +44,23 @@ void inode_sub_rsv_space(struct inode *inode, qsize_t number);
>  
>  void dquot_initialize(struct inode *inode);
>  void dquot_drop(struct inode *inode);
> -struct dquot *dqget(struct super_block *sb, unsigned int id, int type);
> +struct dquot *dqget(struct super_block *sb, qown_t id, enum quota_type type);
>  void dqput(struct dquot *dquot);
>  int dquot_scan_active(struct super_block *sb,
>  		      int (*fn)(struct dquot *dquot, unsigned long priv),
>  		      unsigned long priv);
>  struct dquot *dquot_alloc(struct super_block *sb, int type);
>  void dquot_destroy(struct dquot *dquot);
> +static inline struct dquot *dqgetusr(struct super_block *sb, kuid_t uid)
> +{
> +	qown_t id = { .uid = uid };
> +	return dqget(sb, id, USRQUOTA);
> +}
> +static inline struct dquot *dqgetgrp(struct super_block *sb, kgid_t gid)
> +{
> +	qown_t id = { .gid = gid };
> +	return dqget(sb, id, GRPQUOTA);
> +}
>  
>  int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
>  void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
> @@ -87,15 +97,15 @@ int dquot_writeback_dquots(struct super_block *sb, int type);
>  int dquot_quota_sync(struct super_block *sb, int type);
>  int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
>  int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
> -int dquot_get_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_get_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
> -int dquot_set_dqblk(struct super_block *sb, int type, qid_t id,
> +int dquot_set_dqblk(struct super_block *sb, enum quota_type type, qown_t id,
>  		struct fs_disk_quota *di);
>  
>  int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
>  int dquot_transfer(struct inode *inode, struct iattr *iattr);
>  
> -static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type)
> +static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, enum quota_type type)
>  {
>  	return sb_dqopt(sb)->info + type;
>  }
> diff --git a/init/Kconfig b/init/Kconfig
> index 2a388e5..a0bccce 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -928,8 +928,6 @@ config UIDGID_CONVERTED
>  	depends on IMA = n
>  	depends on EVM = n
>  	depends on FS_POSIX_ACL = n
> -	depends on QUOTA = n
> -	depends on QUOTACTL = n
>  
>  	# Networking
>  	depends on NET_9P = n
> -- 
> 1.7.5.4
> 
-- 
Jan Kara <jack@suse.cz>
SUSE Labs, CR

^ permalink raw reply

* when the MTU interface is modified, the promiscuous mode is reset in gianfar driver
From: 近沢 哲史 @ 2012-08-27  8:38 UTC (permalink / raw)
  To: netdev; +Cc: linux-kernel

Hi

 I am using the gianfar ethernet driver. I am having a problem with the
 interface settings.
 Under promiscuous mode, when the MTU interface is modified, the promiscuous
 mode setting is turned off in gianfar driver when it should not be.
The details are as follows:
 After changing MTU with ifconfig, I could see that the interface flag of
 eth0 is still PROMISC.
 However, when I checked value of RCTL register with ethtool, PROM bit of
 RTCL register is cleared.
 It seems to be cause that is the gfar_init_mac() function, it doesn't set
 the PROM bit after the interface MTU is changed.
 This problem was detected on linux-2.6.32.2, but it seems to same on
 linux-3.6.0-rc3.
Is this behavior on purpose?

I also attach the amended file,I think it would be so.

Signed-off-by: Akifumi Chikazawa <chikazawa.akifu@jp.fujitsu.com>
---
 gianfar.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 4605f72..6991e0e 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -389,6 +389,9 @@ static void gfar_init_mac(struct net_device *ndev)
        if (ndev->features & NETIF_F_HW_VLAN_RX)
                rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT;

+       if (ndev->flags & IFF_PROMISC)
+               rctrl |= RCTRL_PROM;
+
        /* Init rctrl based on our settings */
        gfar_write(&regs->rctrl, rctrl);

-----------
Fujitsu Computer Technologies Limited
Firmware Engineering Dept.

Akifumi Chikazawa
email: chikazawa.akifu@jp.fujitsu.com

^ permalink raw reply related

* Re: [PATCH 00/19] netfilter: IPv6 NAT
From: Florian Weimer @ 2012-08-27  7:33 UTC (permalink / raw)
  To: Andre Tomt; +Cc: kaber, netfilter-devel, netdev
In-Reply-To: <5038233F.7000202@tomt.net>

On 08/25/2012 02:58 AM, Andre Tomt wrote:
> On 09. aug. 2012 22:08, kaber@trash.net wrote:
>> The following patches contain an updated version of IPv6 NAT against
>> Linus' current tree.
>
> Hmmm. Looking in my crystal ball (hi #ipv6!), I predict that if this
> lands in mainline - and thus in consumer CPE/routers eventually - many
> ISP's will have little incentive to actually implement assigning of
> blocks to their consumer users like they "have to" today.

I think the brokenness of IPv6 ND is still sufficient incentive to 
provide the customer with a prefix.  Whether this prefix is constant 
over an extended period of time is a separate question.  Even among 
consumers, preferences vary widely.

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply

* [RFT] testers for CDC-EEM devices wanted
From: Oliver Neukum @ 2012-08-27  7:23 UTC (permalink / raw)
  To: linux-usb, netdev

Hi,

I am looking for people who have a cdc-eem device that emits power
management hints and would be willig to test this patch.

	Regards
		Oliver

>From 499bcc977f13b899cd49a6474843ed3c9086cc0b Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oliver@neukum.org>
Date: Sun, 26 Aug 2012 17:12:06 +0200
Subject: [PATCH] usbnet: Support devices reporting idleness

Some device types support a form of power management in which
the device suggests to the host that the device may be suspended
now. Support for that is best located in usbnet.

Signed-off-by: Oliver Neukum <oneukum@suse.de>
---
 drivers/net/usb/cdc_eem.c  |    4 ++++
 drivers/net/usb/usbnet.c   |   17 +++++++++++++++++
 include/linux/usb/usbnet.h |    2 ++
 3 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index 434d5af..c81e278 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -244,8 +244,12 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 			 *  - suspend: peripheral ready to suspend
 			 *  - response: suggest N millisec polling
 			 *  - response complete: suggest N sec polling
+			 *
+			 * Suspend is reported and maybe heeded.
 			 */
 			case 2:		/* Suspend hint */
+				usbnet_device_suggests_idle(dev);
+				continue;
 			case 3:		/* Response hint */
 			case 4:		/* Response complete hint */
 				continue;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index fd4b26d..38c534a 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1580,10 +1580,27 @@ int usbnet_resume (struct usb_interface *intf)
 			tasklet_schedule (&dev->bh);
 		}
 	}
+
+	if (test_and_clear_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags))
+		usb_autopm_get_interface_no_resume(intf);
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_resume);
 
+/*
+ * Either a subdriver implements manage_power, then it is assumed to always
+ * be ready to be suspended or it reports the readiness to be suspended
+ * explicitly
+ */
+void usbnet_device_suggests_idle(struct usbnet *dev)
+{
+	if (!test_and_set_bit(EVENT_DEVICE_REPORT_IDLE, &dev->flags)) {
+		dev->intf->needs_remote_wakeup = 1;
+		usb_autopm_put_interface_async(dev->intf);
+	}		
+}
+EXPORT_SYMBOL(usbnet_device_suggests_idle);
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h
index f87cf62..ddbbb7d 100644
--- a/include/linux/usb/usbnet.h
+++ b/include/linux/usb/usbnet.h
@@ -68,6 +68,7 @@ struct usbnet {
 #		define EVENT_RX_PAUSED	5
 #		define EVENT_DEV_ASLEEP 6
 #		define EVENT_DEV_OPEN	7
+#		define EVENT_DEVICE_REPORT_IDLE	8
 };
 
 static inline struct usb_driver *driver_of(struct usb_interface *intf)
@@ -160,6 +161,7 @@ extern int usbnet_probe(struct usb_interface *, const struct usb_device_id *);
 extern int usbnet_suspend(struct usb_interface *, pm_message_t);
 extern int usbnet_resume(struct usb_interface *);
 extern void usbnet_disconnect(struct usb_interface *);
+extern void usbnet_device_suggests_idle(struct usbnet *dev);
 
 
 /* Drivers that reuse some of the standard USB CDC infrastructure
-- 
1.7.7

^ permalink raw reply related

* [PATCH 2/5] net:atm:fix up ENOIOCTLCMD error handling
From: Wanlong Gao @ 2012-08-27  7:23 UTC (permalink / raw)
  To: linux-kernel; +Cc: Wanlong Gao, David S. Miller, netdev
In-Reply-To: <1346052196-32682-1-git-send-email-gaowanlong@cn.fujitsu.com>

At commit 07d106d0, Linus pointed out that ENOIOCTLCMD should be
translated as ENOTTY to user mode.

Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
---
 net/atm/resources.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/atm/resources.c b/net/atm/resources.c
index 23f45ce..0447d5d 100644
--- a/net/atm/resources.c
+++ b/net/atm/resources.c
@@ -432,7 +432,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
 			size = dev->ops->ioctl(dev, cmd, buf);
 		}
 		if (size < 0) {
-			error = (size == -ENOIOCTLCMD ? -EINVAL : size);
+			error = (size == -ENOIOCTLCMD ? -ENOTTY : size);
 			goto done;
 		}
 	}
-- 
1.7.12

^ permalink raw reply related

* Re: [PATCHv3 1/4] modem_shm: Add Modem Access Framework
From: Greg KH @ 2012-08-27  6:49 UTC (permalink / raw)
  To: Arun Murthy; +Cc: linux-kernel, netdev, linux-doc, alan
In-Reply-To: <1346046569-8050-2-git-send-email-arun.murthy@stericsson.com>

On Mon, Aug 27, 2012 at 11:19:26AM +0530, Arun Murthy wrote:
> +struct modem {
> +	struct device *dev;

No, this needs to be:
	struct device dev;

Please fix it up to be like that, otherwise you are not using the driver
model properly at all.

> +/**
> + * modem_register - register a modem
> + * @modem_desc: - description for modem
> + * @dev:        - device
> + * @driver_data:- driver specific data
> + *
> + * Register a modem with the modem access framework, so that
> + * it could be used by client drivers for accessing the
> + * modem.
> + */
> +struct modem_dev *modem_register(struct modem_desc *modem_desc,
> +		struct device *dev,
> +		void *driver_data)
> +{
> +	static atomic_t modem_no = ATOMIC_INIT(0);
> +	struct modem_dev *mdev;
> +	int ret;
> +
> +	if (modem_desc == NULL)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (modem_desc->name == NULL || modem_desc->ops == NULL)
> +		return ERR_PTR(-EINVAL);
> +
> +	mdev = kzalloc(sizeof(struct modem_dev), GFP_KERNEL);
> +	if (mdev == NULL)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_lock(&modem_list_mutex);
> +
> +	mutex_init(&mdev->mutex);
> +	mdev->modem_data = driver_data;
> +	mdev->owner = modem_desc->owner;
> +	mdev->desc = modem_desc;
> +	INIT_LIST_HEAD(&mdev->client_list);
> +	INIT_LIST_HEAD(&mdev->modem_list);
> +	BLOCKING_INIT_NOTIFIER_HEAD(&mdev->notifier);
> +
> +	/* mdev->dev.class = &modem_class;*/
> +	mdev->dev.parent = dev;
> +	dev_set_name(&mdev->dev, "modem.%d", atomic_inc_return(&modem_no) - 1);

Use the idr interface instead please.

> +	ret = device_register(&mdev->dev);
> +	if (ret != 0)
> +		goto clean;
> +
> +	dev_set_drvdata(&mdev->dev, mdev);
> +
> +	ret = add_modem_attributes(mdev);
> +	if (ret < 0)
> +		goto backoff;
> +
> +	list_add(&mdev->modem_list, &modem_list);

Hint, you don't need such a list if you use the driver model properly...

> +out:
> +	mutex_unlock(&modem_list_mutex);
> +	return mdev;
> +
> +backoff:
> +	device_unregister(&mdev->dev);
> +	mdev = ERR_PTR(ret);
> +	goto out;
> +
> +clean:
> +	kfree(mdev);
> +	mdev = ERR_PTR(ret);
> +	goto out;
> +}
> +EXPORT_SYMBOL_GPL(modem_register);

You have no "modem_unregister()" call, which, if you did, and actually
tested it out, would show you the problem in the code above (hint, you
really didn't read the documentation I pointed you at previously.)

You are also racing userspace with your device creation, and I can't
tell the difference between a modem_dev and a modem, why have two
different things?

This whole thing needs to be totally reworked, start with the above
comments, and you will see whole sections of this patch just disappear,
as you properly start to use the driver model.

greg k-h

^ permalink raw reply

* [PATCH] usbnet: fix deadlock in resume
From: oliver @ 2012-08-27  6:41 UTC (permalink / raw)
  To: davem, netdev, ming.lei; +Cc: Oliver Neukum, Oliver Neukum, stable

From: Oliver Neukum <oliver@neukum.org>

A usbnet device can share a multifunction device
with a storage device. If the storage device is autoresumed
the usbnet devices also needs to be autoresumed. Allocating
memory with GFP_KERNEL can deadlock in this case.

This should go back into all kernels that have
commit 65841fd5132c3941cdf5df09e70df3ed28323212
That is 3.5

Signed-off-by: Oliver Neukum <oneukum@suse.de>
CC: stable@kernel.org
---
 drivers/net/usb/usbnet.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 8531c1c..fd4b26d 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1573,7 +1573,7 @@ int usbnet_resume (struct usb_interface *intf)
 				netif_device_present(dev->net) &&
 				!timer_pending(&dev->delay) &&
 				!test_bit(EVENT_RX_HALT, &dev->flags))
-					rx_alloc_submit(dev, GFP_KERNEL);
+					rx_alloc_submit(dev, GFP_NOIO);
 
 			if (!(dev->txq.qlen >= TX_QLEN(dev)))
 				netif_tx_wake_all_queues(dev->net);
-- 
1.7.7

^ permalink raw reply related

* [PATCHv3 4/4] Doc: Add u8500_shrm document
From: Arun Murthy @ 2012-08-27  5:49 UTC (permalink / raw)
  To: linux-kernel, netdev, linux-doc, gregkh, alan; +Cc: arun.murthy
In-Reply-To: <1346046569-8050-1-git-send-email-arun.murthy@stericsson.com>

Add document for u8500 shared memory(shrm)and kernel Docbook.

Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
---
 Documentation/DocBook/Makefile         |    2 +-
 Documentation/DocBook/shrm.tmpl        |  125 ++++++++++++++++
 Documentation/modem_shm/u8500_shrm.txt |  254 ++++++++++++++++++++++++++++++++
 3 files changed, 380 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/DocBook/shrm.tmpl
 create mode 100644 Documentation/modem_shm/u8500_shrm.txt

diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index bc3d9f8..673ea06 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -14,7 +14,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
 	    genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
 	    80211.xml debugobjects.xml sh.xml regulator.xml \
 	    alsa-driver-api.xml writing-an-alsa-driver.xml \
-	    tracepoint.xml drm.xml media_api.xml
+	    tracepoint.xml drm.xml media_api.xml shrm.xml
 
 include $(srctree)/Documentation/DocBook/media/Makefile
 
diff --git a/Documentation/DocBook/shrm.tmpl b/Documentation/DocBook/shrm.tmpl
new file mode 100644
index 0000000..400f9b2
--- /dev/null
+++ b/Documentation/DocBook/shrm.tmpl
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+	"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="SHRM">
+ <bookinfo>
+  <title>Shared Memory</title>
+  <authorgroup>
+   <author>
+    <firstname>Arun</firstname>
+    <surname>Murthy</surname>
+    <affiliation>
+     <address>
+      <email>arun.murthy@stericsson.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2009-2010</year>
+   <holder>ST-Ericsson</holder>
+  </copyright>
+
+  <subjectset>
+    <subject>
+      <subjectterm>Linux standard functions</subjectterm>
+    </subject>
+  </subjectset>
+
+  <legalnotice>
+   <!-- Do NOT remove the legal notice below -->
+   <para>
+     Licence terms: GNU General Public Licence (GPL) version 2.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+  <chapter id="intro">
+    <title>Introduction</title>
+    <para>
+	This Documentation describes the ST-Ericsson's adaptation on protocol used for CMT/APE communication when SHaRedMemory is used as IPC link.
+    </para>
+  </chapter>
+
+  <chapter id="design">
+    <title>Design</title>
+    <para>
+	The APE consists Cortex A9 dual core SMP, a multimedia DSP and PRCMU. Modem consists of 2 Cortex R4 ARM processor.
+	The exchange of messages between CMT(Cellular Mobile Terminal) and APE includes copying the data to a shared area DDR.
+	This region is accessible by both CMT and APE. The design includes 2 channels common and audio. Common channel is used for exchanging ISI, RPC and SECURITY messages.
+	udio channel is used for exchanging AUDIO messages. Each channel consists of 2 FIFO. One FIFO for sending message from CMT to APE and other from APE to CMT.
+	ach of these FIFO have write and read pointer shared between APE and CMT. Writer pointer is updated on copying the message to FIFO and reader will read the messages from the read pointer upto the writer pointer. Writer and reader notifications are used to notify the completion of read/write operation(seperate for APE and CMT).
+	river includes 4 queues. Once the messages are sent from CMT to APE it resides in the FIFO and then copied to one of the 4 queues based on the message type(ISI, RPC, AUDIO, SECURITY) and then the net/char device interface fetches this message from the queue and copies to the user space buffer.
+    </para>
+  </chapter>
+
+  <chapter id="concepts">
+    <title>Concepts</title>
+    <para>
+	The user space application sends ISI/RPC/AUDIO/SECURITY messages. ISI is sent through the phonet to shrm driver. For achieving this there are 2 interfaces to the shrm driver. Net interface used for exchanging the ISI message and char interface for RPC, AUDIO and SECURITY messages. On receiving any of these messages from the user space application, it is copied to a memory in kernel space. From here it is then copied to respective FIFO from where the CMT reads the message.
+	CMT(Cellular Mobile Terminal) writes messages to the respective FIFO and thereafter to respective queue. The net/char device copies this message from the queue to the user space buffer.
+    </para>
+  </chapter>
+
+  <chapter id="bugs">
+     <title>Known Bugs And Assumptions</title>
+  <para>
+     <variablelist>
+     <varlistentry>
+       <term>None</term>
+       <listitem>
+         <para>
+		Assumptions
+		1. ApeShmFifo#0 is of 128kB in size. As this is used for transmission except CS audio call data. Expected message size is 1.5kB with a max of 16kB.
+		2. ApeShmFifo#1 is of 4kB in size. This is used for transmission of CS audio call data. Expected message size is 24kb.
+		3. CmtShmFifo#0 is of 128kB in size. As this is used for transmission except CS audio call data. Expected message size is 1.5kB with a max of 16kB.
+		4. CmtShmFifo#1 is of 4kB in size. This is used for transmission of CS audio call data. Expected message size is 24kb.
+		The total size of the FIFO is 264 kB.
+         </para>
+       </listitem>
+     </varlistentry>
+     </variablelist>
+  </para>
+  </chapter>
+
+  <chapter id="pubfunctions">
+     <title>Public Functions Provided</title>
+     <para>
+	This Section lists the API's provided by the SHRM driver to phonet drivers.
+     </para>
+!Edrivers/modem_shm/u8500_shm/shrm_fifo.c
+     <para>
+	This Section lists the API's provided by the SHRM driver used in transmission of RPC, AUDIO and SECURITY messages.
+     </para>
+!Edrivers/modem_shm/u8500_shm/shrm_char.c
+
+  </chapter>
+
+  <chapter id="private">
+    <title>Private Functions</title>
+    <para>
+	This Section lists the functions used internally by the SHRM driver to implement FIFO management. It physically reads/writes data to/from memory.
+    </para>
+!Idrivers/modem_shm/u8500_shm/shrm_fifo.c
+    <para>
+	This Section lists the functions used internally by the SHRM driver to implement the SHRM protocol and handle all interrupt callback.
+    </para>
+!Idrivers/modem_shm/u8500_shm/shrm_protocol.c
+    <para>
+	This Section lists the functions used internally by the SHRM driver to implement Modem-Host communication L1 interface specifications.
+    </para>
+!Idrivers/modem_shm/u8500_shm/shrm_driver.c
+  </chapter>
+
+  <chapter id="Other">
+    <title>Other Data Structures</title>
+    <para>
+	This Section lists some of the Data structure used by the SHRM driver.
+    </para>
+!Idrivers/modem_shm/u8500_shm/shrm_driver.h
+!Idrivers/modem_shm/u8500_shm/shrm_private.h
+  </chapter>
+</book>
diff --git a/Documentation/modem_shm/u8500_shrm.txt b/Documentation/modem_shm/u8500_shrm.txt
new file mode 100644
index 0000000..7bbc0cb
--- /dev/null
+++ b/Documentation/modem_shm/u8500_shrm.txt
@@ -0,0 +1,254 @@
+SHaRed Memory (SHRM)
+--------------------
+Shared memroy IPC driver is the implementation of SHRM protocol used for the
+communication between application processor (APE) of DB8500 SoC and the modem
+subsystem (CMT) of DB8500 SoC.
+
+System Overview
+---------------
+The APE system is made of cortex A9 dual core SMP, a multimedia DSP and Power
+and Reset Control Management Unit(PRCMU).
+The modem subsystem is made of cortex R4 ARM processor.
+
+Shared Memory Structure
+-----------------------
+The exchange of messages between APE and modem includes copying data in the
+shared area of the DDR. The shared memory structure includes 4 FIFO. Each
+communication channel (common or audio) is made of two FIFO's.
+There are 4 types of messages that are communicated between APE and CMT.
+(these are also referred to as L2 header in the shrm protocol)
+	-> ISI message
+	-> RPC message (filesystem)
+	-> Security message
+	-> Audio message
+First 3 of the above messages are transferred through the common channel and
+audio message is transferred via the audio channel. Now each of these 2 channel
+have two FIFO.
+	-> FIFO-1: APE to CMT common channel
+	-> FIFO-2: CMT to APE common channel
+	-> FIFO-3: APE to CMT audio channel
+	-> FIFO-4: CMT to APE audio channel
+Each of these fifo'a have 4 pointers.
+	-> Shared read pointer
+	-> Shared write pointer
+	-> local read pointer
+	-> local write pointer
+The read/write permission of the above 4 pointer depends on the fifo.
+Size of common fifo is 128KB each and that of audio fifo is 4KB each.
+
+Notification
+------------
+The SHRM protocol uses interrupt generation register in CMT to support crossed
+notifications. For APE to CMT notifications, the APE sets a corresponding bit
+in the interrupt generation register of CMT. This triggers an interrupt in the
+cortex R4 of CMT. This interrupt generation module is regerred to as General
+Output Port(GOP) register. The register is a standard GOP, SET/CLEAR/TOGGLE.
+Below are the list of interrupts:
+	AcMsgPendNotif:	APE notifies CMT that it has written some message to the
+			fifo or that there are some messages unread by CMT.
+	AcReadNotif:	CMT notifies APE that it has read the message.
+	CaMsgPendNotif: CMT notifies APE that it has written some message to the
+			fifo or that there are some messages unread by APE.
+	CaReadNotif:	APE notifies CMT that it has read the message.
+	AcWakeReq:	APE has some messages to communicate with CMT and hence
+			requests CMT to wake up.
+	AcWakeAck:	CMT acknowledges to AcWakeReq after waking up by sending
+			AcWakeAck.
+	AcSleepReq:	APE notifies CMT that it has no more messages to
+			communicate and if required CMT can sleep.
+	AcSleepAck:	CMT acknowledges to AcSleepReq.
+	CaWakeReq:	CMT has some messages to communicate with APE and hence
+			requests APE to wakeup.
+	CaWakeAck:	APE acknowledges to CaWakeReq after waking up by sending
+			this interrupt.
+	CaResetReq:	CMT notifies APE that it has reset.
+
+Note: There are 2 copies of first 4 interrupts mentioned above each representing
+for common and audio channel.
+Notation used is 0->common channel and 1->audio channel
+
+FIFO Operation
+--------------
+Initially all the 4 pointer are reset to 0. Now assume that APE wants to send
+some data to modem then it writes to the corresponding fifo starting from the
+address in 'Shared write pointer'. Now CMT will start reading this message
+starting from the address mentioned in 'Shared read pointer' and will continue
+reading the message until it meets the address in 'Shared write pointer' and
+'Shared read pointer' is updated accordingly.
+Consider that APE has written a message in FIFO and CMT has not yet read that
+message, in the mean time APE has another message, so APE will write to the
+shared memory and now instead of updating the 'Shared write pointer', will
+update 'local write pointer' and keep on writing the messages thereby not
+blocking the messages that are sent to the shrm driver through modem has not
+yet read the previous message.
+
+SHRM Message format
+-------------------
+Message is made of a header plus a data. Header is made of several fields which
+includes the L1 and L2 header.
+
+L1 Header:
+	L1 header is used in the message sent by the writer during the
+	initialization of the SHRM protocol. Available L1 headers are
+		BOOT_INFO_REQ - CMT sends this to APE
+		BOOT_INFO_RESP - APE sends this to CMT
+		MESSAGE - Used by both APE and CMT while communicating.
+	The first two L1 headers are used only during the boot and it includes
+	no other data apart from the L1 header.
+
+	BOOT_INFO_REQ
+		_________________________________________
+		|31 ... 28|27 ....... 16|15 ... 8|7 ... 0|  bits
+		-----------------------------------------
+		|cmd 0x01 | Reserved    |config  |Version|
+		|         |             |   Info | Id    |
+
+	BOOT_INFO_RESP
+		_________________________________________
+		|31 ... 28|27 ....... 16|15 ... 8|7 ... 0|  bits
+		-----------------------------------------
+		|cmd 0x02 | Reserved    |config  |Version|
+		|         |             |   Info | Id    |
+
+	MESSAGE
+		_________________________________________
+		|31 ... 28|27 ....... 20|19 ........... 0|  bits
+		-----------------------------------------
+		|cmd 0x03 | Counter    | Length of data |
+		|         |            |                |
+
+L2 Header:
+	L2 header or L2 mux is used to route specific type of message on
+	specific channel.
+		ISI -> 0
+		RPC -> 1
+		Audio -> 2
+		Security -> 3
+
+SHRM Boot Sequence
+------------------
+	SHRM driver is a communication between two entities APE and CMT. Hence
+there has to be some sync during boot so that a communication can exist. This
+is first initiated by the CMT:-
+
+	CMT			APE
+	 -------CaWakeReq------->
+
+	 <------CaWakeAck--------
+
+	 ---msg BOOT_INFO_REQ--->
+
+	 <---BOOT_INFO_RESP msg--
+
+APE Initiated communication
+---------------------------
+	APE			CMT
+	 -------AcWakeReq-------->
+
+	 <------AcWakeAck---------
+
+	 -----AcMsgPendNotif----->
+
+	 <------AcReadNotif-------
+
+	 -----AcMsgPendNotif----->
+
+	 <------AcReadNotif-------
+			|
+			|
+	 -------AcSleepReq------->
+
+	 <------AcSleepAck--------
+
+SHRM driver interfaces
+----------------------
+The application using the shrm driver is audio, security, filesystem and the
+android RIL. All of these exist in the user space. Hence in order to pass this
+message to the user space there exist two types of interface
+	Character interface
+	Network interface
+
+Character Interface
+	Character devices are created for RPC, Security and Audi with the major	
+	ID being the L2 header. Message queues are created for each of available
+	L2 headers, which will be used during the Rx for copying the message
+	from the shared memory. Further the user space application will reques
+	for this message from the character deivce points which will fet the
+	data from the corresponding queue and provide it to the user space.
+	For the Tx path again the data is to be copied from the user space to
+	the shared memory. There exist static memory for each L2 header or
+	message type each of size 512k. This statch memeory will be used in the
+	Tx path. First the message will be copied from user space to this static
+	memory and then passed on the the shrm protocol where it will be moved
+	to the shared memory.
+	All operations like adding message to queue, removing messages to queue
+	resides in this file.
+Network Interface
+	The CMT used in u8500 platform is the Renessas modem and hence will use
+	phonet for Tx and Rx of the ISI messages. A network driver is registered
+	with name 'shrm0'. On Tx path the message comes via the phonet to the
+	shrm network interface driver. The same is passed to the shrm protocol
+	to transmit it to the modem. On Rx path ISI message is copied to skbuff
+	and corresponding phonet addr is added. This message is routed via
+	phonet, network and then to the user space from the socket depending
+	on the type od message, i.e ISI message or data packets.
+
+Modem Silent Reset
+------------------
+On getting a modem reset interrupt from CMT, APE will inform all its clients via
+netlink so that none of the clients will further send any messages to send it to
+the CMT. Then shrm driver will disable all interrupts reset its state machine,
+clear all message queues, stop any communication if any in progress and waits
+for the modem to book. Since the modem reset status is sent via netlink to the
+user clients, the client responsible for collecting modem dump and reloading
+CMT image will be done and then CMT will be released from reset wherein it
+starts booting up.
+
+Implementation
+--------------
+The shrm protocol driver is spread over many files:
+	shrm_driver.c
+	shrm_protocol.c
+	shrm_fifo.c
+	shrm_driver.h
+	shrm_char.c
+	shrm_net.c
+	shrm_driver.h
+	shrm_config.h
+	shrm_net.h
+	shrm_private.h
+	shrm.h
+
+shrm_driver.c
+-------------
+This file is the main entry for the shrm driver and includes:
+	-> memory ioremapping (shared memory)
+	-> work queue initialization
+	-> registering of interrupts
+	-> suspend/resume control
+		The criteria for shrm driver suspend is that AcSleepReq and
+		CaSleepReq should be set and the Rx message queue for RPC,
+		Security should be empty.
+	-> Rx calback handler - On modem sending any message based on the
+	   channel the callback handler gets executed which will add the message
+	   to the corresponding message queue or call the shrm network interface
+	   if its an ISI message, which will route the packets via phonet.
+
+shrm_protocol.c
+---------------
+This file includes the shrm protocol implementation and also includes Modem
+Silent Reset(MSR) implementation. Interrupt handlers for all interrupts raised
+by modem are present in this file. This file makes access to the shared memory
+for read and write process. Hence a state machine and prorper check for the shrm
+protocol is validated.
+
+shrm_fifo.c
+-----------
+As said shared memory is classified into 4 FIFO's and hence data read or written
+to the shared memoery is nothing by reading/writing to the FIFO. This operations
+made on FIFO is present in this file. It includes the shared and local reader
+and writer pointer, all updation of this pointer happends in this file. The fifo
+is desinged in a manner to sufficiently hold the data in it without encountering
+the fifo full situation.
+
+For futher information on implementation details refer the kernel doc.
-- 
1.7.4.3

^ permalink raw reply related

* [PATCHv3 3/4] modem_shm: u8500-shm: U8500 Shared Memory Driver
From: Arun Murthy @ 2012-08-27  5:49 UTC (permalink / raw)
  To: linux-kernel, netdev, linux-doc, gregkh, alan; +Cc: arun.murthy
In-Reply-To: <1346046569-8050-1-git-send-email-arun.murthy@stericsson.com>

The communication between APE and CMT in u8500 is by means of a shared DDR.
Since its a shared memory, this driver implements shrm protocol.

Signed-off-by: Arun Murthy <arun.murthy@stericsson.com>
---
 drivers/modem_shm/Kconfig                   |    2 +
 drivers/modem_shm/Makefile                  |    1 +
 drivers/modem_shm/u8500_shm/Kconfig         |   43 +
 drivers/modem_shm/u8500_shm/Makefile        |    7 +
 drivers/modem_shm/u8500_shm/shrm.h          |   23 +
 drivers/modem_shm/u8500_shm/shrm_char.c     |  816 ++++++++++++++
 drivers/modem_shm/u8500_shm/shrm_config.h   |  114 ++
 drivers/modem_shm/u8500_shm/shrm_driver.c   |  733 ++++++++++++
 drivers/modem_shm/u8500_shm/shrm_driver.h   |  226 ++++
 drivers/modem_shm/u8500_shm/shrm_fifo.c     |  838 ++++++++++++++
 drivers/modem_shm/u8500_shm/shrm_ioctl.h    |   43 +
 drivers/modem_shm/u8500_shm/shrm_net.c      |  313 ++++++
 drivers/modem_shm/u8500_shm/shrm_net.h      |   46 +
 drivers/modem_shm/u8500_shm/shrm_private.h  |  184 +++
 drivers/modem_shm/u8500_shm/shrm_protocol.c | 1591 +++++++++++++++++++++++++++
 15 files changed, 4980 insertions(+), 0 deletions(-)
 create mode 100644 drivers/modem_shm/u8500_shm/Kconfig
 create mode 100644 drivers/modem_shm/u8500_shm/Makefile
 create mode 100644 drivers/modem_shm/u8500_shm/shrm.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_char.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_config.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_driver.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_fifo.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_ioctl.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.c
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_net.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_private.h
 create mode 100644 drivers/modem_shm/u8500_shm/shrm_protocol.c

diff --git a/drivers/modem_shm/Kconfig b/drivers/modem_shm/Kconfig
index f59d3dc..dc74597 100644
--- a/drivers/modem_shm/Kconfig
+++ b/drivers/modem_shm/Kconfig
@@ -18,3 +18,5 @@ config MODEM_U8500
 	 Application processor.
 
 	 If unsure, say N.
+
+source "drivers/modem_shm/u8500_shm/Kconfig"
diff --git a/drivers/modem_shm/Makefile b/drivers/modem_shm/Makefile
index a9aac0f..eeef578 100644
--- a/drivers/modem_shm/Makefile
+++ b/drivers/modem_shm/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MODEM_SHM)		:= modem_access.o
 obj-$(CONFIG_MODEM_U8500)	+= modem_u8500.o
+obj-$(CONFIG_U8500_SHRM)	+= u8500_shm/
diff --git a/drivers/modem_shm/u8500_shm/Kconfig b/drivers/modem_shm/u8500_shm/Kconfig
new file mode 100644
index 0000000..465c8bb
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/Kconfig
@@ -0,0 +1,43 @@
+#
+# SHM HW kernel configuration
+#
+config U8500_SHRM
+	bool "U8500 SHRM hardware driver"
+	depends on ARCH_U8500 && PHONET && MODEM_U8500
+	default Y
+	---help---
+	  If you say Y here, you will enable the STN8500 SHM hardware driver.
+
+	  If unsure, say N.
+choice
+	prompt "Modem Image Version"
+	depends on U8500_SHRM
+	default SHRM_V1_UPDATES_VERSION
+
+	config SHRM_V1_UPDATES_VERSION
+	depends on U8500_SHRM
+	bool "SHRM V1 UPDATES"
+	help
+	 Modem Images with V1 Updates
+
+endchoice
+
+config U8500_SHRM_LOOP_BACK
+	bool "U8500 SHRM loopback"
+	depends on U8500_SHRM
+	default n
+	---help---
+	  If you say Y here, you will enable the shm loopback
+
+	  If unsure, say N.
+
+config U8500_SHRM_MODEM_SILENT_RESET
+	bool "U8500 SHRM Modem Silent Reset"
+	depends on U8500_SHRM
+	default n
+	---help---
+	  If you say Y here, you will enable the modem silent reset feature
+
+	  If unsure, say N.
+
+
diff --git a/drivers/modem_shm/u8500_shm/Makefile b/drivers/modem_shm/u8500_shm/Makefile
new file mode 100644
index 0000000..aefd315
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for U8500 SHRM drivers
+#
+
+u8500_shrm-objs := 	shrm_driver.o shrm_fifo.o shrm_protocol.o shrm_net.o shrm_char.o
+
+obj-$(CONFIG_U8500_SHRM)	+= u8500_shrm.o
diff --git a/drivers/modem_shm/u8500_shm/shrm.h b/drivers/modem_shm/u8500_shm/shrm.h
new file mode 100644
index 0000000..5b41cec
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHM_DRIVER_IF_H__
+#define __SHM_DRIVER_IF_H__
+
+#include <linux/device.h>
+
+/* forward declaration */
+struct shrm_dev;
+
+typedef void (*rx_cb)(void *data, unsigned int length);
+typedef void (*received_msg_handler)(unsigned char l2_header,
+			void *msg_ptr, unsigned int length,
+			struct shrm_dev *shrm);
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_char.c b/drivers/modem_shm/u8500_shm/shrm_char.c
new file mode 100644
index 0000000..c8671ca
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_char.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_ioctl.h"
+#include "shrm.h"
+
+#define NAME "IPC_ISA"
+/* L2 header for rtc_calibration device is 0xC8 and hence 0xC8 + 1 = 201 */
+#define MAX_L2_HEADERS 201
+
+#define SIZE_OF_FIFO (512*1024)
+
+static u8 message_fifo[ISA_DEVICES][SIZE_OF_FIFO];
+
+static u8 wr_rpc_msg[10*1024];
+static u8 wr_sec_msg[10*1024];
+static u8 wr_audio_msg[10*1024];
+static u8 wr_rtc_cal_msg[100];
+
+struct map_device {
+	u8 l2_header;
+	u8 idx;
+	char *name;
+};
+
+static struct map_device map_dev[] = {
+	{ISI_MESSAGING, 0, "isi"},
+	{RPC_MESSAGING, 1, "rpc"},
+	{AUDIO_MESSAGING, 2, "modemaudio"},
+	{SECURITY_MESSAGING, 3, "sec"},
+	{COMMON_LOOPBACK_MESSAGING, 4, "common_loopback"},
+	{AUDIO_LOOPBACK_MESSAGING, 5, "audio_loopback"},
+	{CIQ_MESSAGING, 6, "ciq"},
+	{RTC_CAL_MESSAGING, 7, "rtc_calibration"},
+};
+
+/* major number at load time */
+static int major;
+/* global fops mutex */
+static DEFINE_MUTEX(isa_lock);
+
+/**
+ * shrm_get_cdev_index() - return the index mapped to l2 header
+ * @l2_header:	L2 header
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the index for the provided L2 header in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_index(u8 l2_header)
+{
+	u8 cnt;
+	for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+		if (map_dev[cnt].l2_header == l2_header)
+			return map_dev[cnt].idx;
+	}
+	return -EINVAL;
+}
+
+/**
+ * shrm_get_cdev_l2header() - return l2_header mapped to the index
+ * @idx:	index
+ *
+ * struct map_device maps the index(count) with the device L2 header.
+ * This function returns the L2 header for the given index in case
+ * of success else -ve value.
+ */
+int shrm_get_cdev_l2header(u8 idx)
+{
+	u8 cnt;
+	for (cnt = 0; cnt < ISA_DEVICES; cnt++) {
+		if (map_dev[cnt].idx == idx)
+			return map_dev[cnt].l2_header;
+	}
+	return -EINVAL;
+}
+
+void shrm_char_reset_queues(struct shrm_dev *shrm)
+{
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context;
+	struct queue_element *cur_msg = NULL;
+	struct list_head *cur_msg_ptr = NULL;
+	struct list_head *msg_ptr;
+	struct message_queue *q;
+	int no_dev;
+
+	dev_info(shrm->dev, "%s: Resetting char device queues\n", __func__);
+	isa_context = shrm->isa_context;
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		isadev = &isa_context->isadev[no_dev];
+		q = &isadev->dl_queue;
+
+		spin_lock_bh(&q->update_lock);
+		/* empty out the msg queue */
+		list_for_each_safe(cur_msg_ptr, msg_ptr, &q->msg_list) {
+			cur_msg = list_entry(cur_msg_ptr,
+					struct queue_element, entry);
+			list_del(cur_msg_ptr);
+			kfree(cur_msg);
+		}
+
+		/* reset the msg queue pointers */
+		q->size = SIZE_OF_FIFO;
+		q->readptr = 0;
+		q->writeptr = 0;
+		q->no = 0;
+
+		/* wake up the blocking read/select */
+		atomic_set(&q->q_rp, 1);
+		wake_up_interruptible(&q->wq_readable);
+
+		spin_unlock_bh(&q->update_lock);
+	}
+}
+
+/**
+ * create_queue() - To create FIFO for Tx and Rx message buffering.
+ * @q:		message queue.
+ * @devicetype:	device type 0-isi,1-rpc,2-audio,3-security,
+ * 4-common_loopback, 5-audio_loopback.
+ * @shrm:	pointer to the shrm device information structure
+ *
+ * This function creates a FIFO buffer of n_bytes size using
+ * dma_alloc_coherent(). It also initializes all queue handling
+ * locks, queue management pointers. It also initializes message list
+ * which occupies this queue.
+ */
+static int create_queue(struct message_queue *q, u32 devicetype,
+						struct shrm_dev *shrm)
+{
+	q->fifo_base = (u8 *)&message_fifo[devicetype];
+	q->size = SIZE_OF_FIFO;
+	q->readptr = 0;
+	q->writeptr = 0;
+	q->no = 0;
+	q->shrm = shrm;
+	spin_lock_init(&q->update_lock);
+	INIT_LIST_HEAD(&q->msg_list);
+	init_waitqueue_head(&q->wq_readable);
+	atomic_set(&q->q_rp, 0);
+
+	return 0;
+}
+
+static void delete_queue(struct message_queue *q)
+{
+	q->size = 0;
+	q->readptr = 0;
+	q->writeptr = 0;
+}
+
+/**
+ * add_msg_to_queue() - Add a message inside queue
+ * @q:		message queue
+ * @size:	size in bytes
+ *
+ * This function tries to allocate n_bytes of size in FIFO q.
+ * It returns negative number when no memory can be allocated
+ * currently.
+ */
+int add_msg_to_queue(struct message_queue *q, u32 size)
+{
+	struct queue_element *new_msg = NULL;
+	struct shrm_dev *shrm = q->shrm;
+
+	dev_dbg(shrm->dev, "%s IN q->writeptr=%d\n", __func__, q->writeptr);
+	new_msg = kmalloc(sizeof(struct queue_element), GFP_ATOMIC);
+	if (new_msg == NULL) {
+		dev_err(shrm->dev, "unable to allocate memory\n");
+		return -ENOMEM;
+	}
+	new_msg->offset = q->writeptr;
+	new_msg->size = size;
+	new_msg->no = q->no++;
+
+	/* check for overflow condition */
+	if (q->readptr <= q->writeptr) {
+		if (((q->writeptr-q->readptr) + size) >= q->size) {
+			dev_err(shrm->dev, "Buffer overflow !!\n");
+			BUG_ON(((q->writeptr-q->readptr) + size) >= q->size);
+		}
+	} else {
+		if ((q->writeptr + size) >= q->readptr) {
+			dev_err(shrm->dev, "Buffer overflow !!\n");
+			BUG_ON((q->writeptr + size) >= q->readptr);
+		}
+	}
+	q->writeptr = (q->writeptr + size) % q->size;
+	if (list_empty(&q->msg_list)) {
+		list_add_tail(&new_msg->entry, &q->msg_list);
+		/* There can be 2 blocking calls read  and another select */
+		atomic_set(&q->q_rp, 1);
+		wake_up_interruptible(&q->wq_readable);
+	} else
+		list_add_tail(&new_msg->entry, &q->msg_list);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+}
+
+/**
+ * remove_msg_from_queue() - To remove a message from the msg queue.
+ * @q:	message queue
+ *
+ * This function delets a message from the message list associated with message
+ * queue q and also updates read ptr.
+ * If the message list is empty, then, event is set to block the select and
+ * read calls of the paricular queue.
+ *
+ * The message list is FIFO style and message is always added to tail and
+ * removed from head.
+ */
+int remove_msg_from_queue(struct message_queue *q)
+{
+	struct queue_element *old_msg = NULL;
+	struct shrm_dev *shrm = q->shrm;
+	struct list_head *msg_ptr = NULL;
+	struct list_head *old_msg_ptr = NULL;
+
+	dev_dbg(shrm->dev, "%s IN q->readptr %d\n", __func__, q->readptr);
+
+	list_for_each_safe(old_msg_ptr, msg_ptr, &q->msg_list) {
+		old_msg = list_entry(old_msg_ptr, struct queue_element, entry);
+		if (old_msg == NULL) {
+			dev_err(shrm->dev, "no message found\n");
+			return -EFAULT;
+		}
+		list_del(old_msg_ptr);
+		q->readptr = (q->readptr + old_msg->size)%q->size;
+		kfree(old_msg);
+		break;
+	}
+	if (list_empty(&q->msg_list)) {
+		dev_dbg(shrm->dev, "List is empty setting RP= 0\n");
+		atomic_set(&q->q_rp, 0);
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+}
+
+/**
+ * get_size_of_new_msg() - retrieve new message from message list
+ * @q:	message queue
+ *
+ * This function will retrieve most recent message from the corresponding
+ * queue list. New message is always retrieved from head side.
+ * It returns new message no, offset if FIFO and size.
+ */
+int get_size_of_new_msg(struct message_queue *q)
+{
+	struct queue_element *new_msg = NULL;
+	struct list_head *msg_list;
+	struct shrm_dev *shrm = q->shrm;
+	int size = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	spin_lock_bh(&q->update_lock);
+	list_for_each(msg_list, &q->msg_list) {
+		new_msg = list_entry(msg_list, struct queue_element, entry);
+		if (new_msg == NULL) {
+			spin_unlock_bh(&q->update_lock);
+			dev_err(shrm->dev, "no message found\n");
+			return -EFAULT;
+		}
+		size = new_msg->size;
+		break;
+	}
+	spin_unlock_bh(&q->update_lock);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return size;
+}
+
+/**
+ * isa_select() - shrm char interface driver select interface
+ * @filp:	file descriptor pointer
+ * @wait:	poll_table_struct pointer
+ *
+ * This function is used to perform non-blocking read operations. It allows
+ * a process to determine whether it can read from one or more open files
+ * without blocking. These calls can also block a process until any of a
+ * given set of file descriptors becomes available for reading.
+ * If a file is ready to read, POLLIN | POLLRDNORM bitmask is returned.
+ * The driver method is called whenever the user-space program performs a select
+ * system call involving a file descriptor associated with the driver.
+ */
+static u32 isa_select(struct file *filp,
+				struct poll_table_struct *wait)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	u32 mask = 0;
+	u32 m = iminor(filp->f_path.dentry->d_inode);
+	u8 idx = shrm_get_cdev_index(m);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (shrm->msr_flag)
+		return -ENODEV;
+
+	if (isadev->device_id != idx)
+			return -1;
+
+	q = &isadev->dl_queue;
+	poll_wait(filp, &q->wq_readable, wait);
+	if (atomic_read(&q->q_rp) == 1)
+		mask = POLLIN | POLLRDNORM;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return mask;
+}
+
+/**
+ * isa_read() - Read from device
+ * @filp:	file descriptor
+ * @buf:	user buffer pointer
+ * @len:	size of requested data transfer
+ * @ppos:	not used
+ *
+ * It reads a oldest message from queue and copies it into user buffer and
+ * returns its size.
+ * If there is no message present in queue, then it blocks until new data is
+ * available.
+ */
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+	u32 size = 0;
+	int ret;
+	char *psrc;
+	struct isadev_context *isadev = (struct isadev_context *)
+							filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	u32 msgsize;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	q = &isadev->dl_queue;
+
+	if (shrm->msr_flag) {
+		atomic_set(&q->q_rp, 0);
+		return -ENODEV;
+	}
+
+	spin_lock_bh(&q->update_lock);
+	if (list_empty(&q->msg_list)) {
+		spin_unlock_bh(&q->update_lock);
+		dev_dbg(shrm->dev, "Waiting for Data\n");
+		if (wait_event_interruptible(q->wq_readable,
+				atomic_read(&q->q_rp) == 1))
+			return -ERESTARTSYS;
+	} else
+		spin_unlock_bh(&q->update_lock);
+
+	if (shrm->msr_flag) {
+		atomic_set(&q->q_rp, 0);
+		return -ENODEV;
+	}
+
+	msgsize = get_size_of_new_msg(q);
+
+	if (len < msgsize)
+		return -EINVAL;
+
+	if ((q->readptr + msgsize) >= q->size) {
+		dev_dbg(shrm->dev, "Inside Loop Back\n");
+		psrc = (char *)buf;
+		size = (q->size-q->readptr);
+		/* Copy First Part of msg */
+		if (copy_to_user(psrc,
+				(u8 *)(q->fifo_base + q->readptr),
+				size)) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		if (copy_to_user(psrc,
+				(u8 *)(q->fifo_base),
+				(msgsize-size))) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+	} else {
+		if (copy_to_user(buf,
+				(u8 *)(q->fifo_base + q->readptr),
+				msgsize)) {
+			dev_err(shrm->dev, "copy_to_user failed\n");
+			return -EFAULT;
+		}
+	}
+	spin_lock_bh(&q->update_lock);
+	ret = remove_msg_from_queue(q);
+	if (ret < 0) {
+		dev_err(shrm->dev,
+				"Remove msg from message queue failed\n");
+		msgsize = ret;
+	}
+	spin_unlock_bh(&q->update_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return msgsize;
+}
+
+/**
+ * isa_write() - Write to shrm char device
+ * @filp:	file descriptor
+ * @buf:	user buffer pointer
+ * @len:	size of requested data transfer
+ * @ppos:	not used
+ *
+ * It checks if there is space available in queue, and copies the message
+ * inside queue. If there is no space, it blocks until space becomes available.
+ * It also schedules transfer thread to transmit the newly added message.
+ */
+ssize_t isa_write(struct file *filp, const char __user *buf,
+				 size_t len, loff_t *ppos)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct message_queue *q;
+	void *addr = 0;
+	int err, l2_header;
+	int ret = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	q = &isadev->dl_queue;
+	l2_header = shrm_get_cdev_l2header(isadev->device_id);
+	if (l2_header < 0) {
+		dev_err(shrm->dev, "failed to get L2 header\n");
+		return l2_header;
+	}
+
+	switch (l2_header) {
+	case RPC_MESSAGING:
+		dev_dbg(shrm->dev, "RPC\n");
+		addr = (void *)wr_rpc_msg;
+		break;
+	case AUDIO_MESSAGING:
+		dev_dbg(shrm->dev, "Audio\n");
+		addr = (void *)wr_audio_msg;
+		break;
+	case SECURITY_MESSAGING:
+		dev_dbg(shrm->dev, "Security\n");
+		addr = (void *)wr_sec_msg;
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		dev_dbg(shrm->dev, "Common loopback\n");
+		addr = isadev->addr;
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		dev_dbg(shrm->dev, "Audio loopback\n");
+		addr = isadev->addr;
+		break;
+	case CIQ_MESSAGING:
+		dev_dbg(shrm->dev, "CIQ\n");
+		addr = isadev->addr;
+		break;
+	case RTC_CAL_MESSAGING:
+		dev_dbg(shrm->dev, "isa_write(): RTC Calibration\n");
+		addr = (void *)wr_rtc_cal_msg;
+		break;
+	default:
+		dev_dbg(shrm->dev, "Wrong device\n");
+		return -EFAULT;
+	}
+
+	if (copy_from_user(addr, buf, len)) {
+		dev_err(shrm->dev, "copy_from_user failed\n");
+		return -EFAULT;
+	}
+	/* Write msg to Fifo */
+	if ((l2_header == AUDIO_MESSAGING) ||
+			(l2_header == AUDIO_LOOPBACK_MESSAGING)) {
+		mutex_lock(&shrm->isa_context->tx_audio_mutex);
+		err = shrm_write_msg(shrm, l2_header, addr, len);
+		if (!err)
+			ret = len;
+		else
+			ret = err;
+		mutex_unlock(&shrm->isa_context->tx_audio_mutex);
+	} else {
+		spin_lock_bh(&shrm->isa_context->common_tx);
+		err = shrm_write_msg(shrm, l2_header, addr, len);
+		if (!err)
+			ret = len;
+		else
+			ret = err;
+		spin_unlock_bh(&shrm->isa_context->common_tx);
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * isa_close() - Close device file
+ * @inode:	structure is used by the kernel internally to represent files
+ * @filp:	device file descriptor
+ *
+ * This function deletes structues associated with this file, deletes
+ * queues, flushes and destroys workqueus and closes this file.
+ * It also unregisters itself from l2mux driver.
+ */
+static int isa_close(struct inode *inode, struct file *filp)
+{
+	struct isadev_context *isadev = filp->private_data;
+	struct shrm_dev *shrm = isadev->dl_queue.shrm;
+	struct isa_driver_context *isa_context = shrm->isa_context;
+	u8 m;
+	int idx;
+
+	mutex_lock(&isa_lock);
+	m = iminor(filp->f_path.dentry->d_inode);
+	idx = shrm_get_cdev_index(m);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		mutex_unlock(&isa_lock);
+		return idx;
+	}
+	dev_dbg(shrm->dev, "isa_close %d", m);
+
+	if (atomic_dec_and_test(&isa_context->is_open[idx])) {
+		atomic_inc(&isa_context->is_open[idx]);
+		dev_err(shrm->dev, "Device not opened yet\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	}
+	atomic_set(&isa_context->is_open[idx], 1);
+
+	switch (m) {
+	case RPC_MESSAGING:
+		dev_info(shrm->dev, "Close RPC_MESSAGING Device\n");
+		break;
+	case AUDIO_MESSAGING:
+		dev_info(shrm->dev, "Close AUDIO_MESSAGING Device\n");
+		break;
+	case SECURITY_MESSAGING:
+		dev_info(shrm->dev, "CLose SECURITY_MESSAGING Device\n");
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		dev_info(shrm->dev, "Close COMMON_LOOPBACK_MESSAGING Device\n");
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		dev_info(shrm->dev, "Close AUDIO_LOOPBACK_MESSAGING Device\n");
+		break;
+	case CIQ_MESSAGING:
+		dev_info(shrm->dev, "Close CIQ_MESSAGING Device\n");
+		break;
+	case RTC_CAL_MESSAGING:
+		dev_info(shrm->dev, "Close RTC_CAL_MESSAGING Device\n");
+		break;
+	default:
+		dev_info(shrm->dev, "No such device present\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	};
+	kfree(isadev->addr);
+	mutex_unlock(&isa_lock);
+	return 0;
+}
+/**
+ * isa_open() -  Open device file
+ * @inode:	structure is used by the kernel internally to represent files
+ * @filp:	device file descriptor
+ *
+ * This function performs initialization tasks needed to open SHRM channel.
+ * Following tasks are performed.
+ * -return if device is already opened
+ * -create uplink FIFO
+ * -create downlink FIFO
+ * -init delayed workqueue thread
+ * -register to l2mux driver
+ */
+static int isa_open(struct inode *inode, struct file *filp)
+{
+	int err = 0;
+	u8 m;
+	int idx;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context = container_of(
+						inode->i_cdev,
+						struct isa_driver_context,
+						cdev);
+	struct shrm_dev *shrm = isa_context->isadev->dl_queue.shrm;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_boot_state() != BOOT_DONE) {
+		dev_err(shrm->dev, "Boot is not done\n");
+		return -EBUSY;
+	}
+	mutex_lock(&isa_lock);
+	m = iminor(inode);
+
+	if ((m != RPC_MESSAGING) &&
+				(m != AUDIO_LOOPBACK_MESSAGING) &&
+				(m != COMMON_LOOPBACK_MESSAGING) &&
+				(m != AUDIO_MESSAGING) &&
+				(m != SECURITY_MESSAGING) &&
+				(m != CIQ_MESSAGING) &&
+				(m != RTC_CAL_MESSAGING)) {
+		dev_err(shrm->dev, "No such device present\n");
+		mutex_unlock(&isa_lock);
+		return -ENODEV;
+	}
+	idx = shrm_get_cdev_index(m);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		mutex_unlock(&isa_lock);
+		return idx;
+	}
+	if (!atomic_dec_and_test(&isa_context->is_open[idx])) {
+		atomic_inc(&isa_context->is_open[idx]);
+		dev_err(shrm->dev, "Device already opened\n");
+		mutex_unlock(&isa_lock);
+		return -EBUSY;
+	}
+	isadev = &isa_context->isadev[idx];
+	filp->private_data = isadev;
+
+	switch (m) {
+	case RPC_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open RPC_MESSAGING Device\n");
+		break;
+	case AUDIO_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open AUDIO_MESSAGING Device\n");
+		break;
+	case SECURITY_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open SECURITY_MESSAGING Device\n");
+		break;
+	case COMMON_LOOPBACK_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open COMMON_LOOPBACK_MESSAGING Device\n");
+		break;
+	case AUDIO_LOOPBACK_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open AUDIO_LOOPBACK_MESSAGING Device\n");
+		break;
+	case CIQ_MESSAGING:
+		isadev->addr = kzalloc(10 * 1024, GFP_KERNEL);
+		if (!isadev->addr) {
+			mutex_unlock(&isa_lock);
+			return -ENOMEM;
+		}
+		dev_info(shrm->dev, "Open CIQ_MESSAGING Device\n");
+		break;
+	case RTC_CAL_MESSAGING:
+		isadev->addr = NULL;
+		dev_info(shrm->dev, "Open RTC_CAL_MESSAGING Device\n");
+		break;
+	};
+
+	mutex_unlock(&isa_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return err;
+}
+
+static struct file_operations isa_fops = {
+	.owner = THIS_MODULE,
+	.open = isa_open,
+	.release = isa_close,
+	.read = isa_read,
+	.write = isa_write,
+	.poll = isa_select,
+};
+
+/**
+ * isa_init() - module insertion function
+ * @shrm:	pointer to the shrm device information structure
+ *
+ * This function registers module as a character driver using
+ * register_chrdev_region() or alloc_chrdev_region. It adds this
+ * driver to system using cdev_add() call. Major number is dynamically
+ * allocated using alloc_chrdev_region() by default or left to user to specify
+ * it during load time. For this variable major is used as module_param
+ * Nodes to be created using
+ * mknod /dev/isi c $major 0
+ * mknod /dev/rpc c $major 1
+ * mknod /dev/audio c $major 2
+ * mknod /dev/sec c $major 3
+ */
+int isa_init(struct shrm_dev *shrm)
+{
+	dev_t	dev_id;
+	int	retval, no_dev;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context;
+
+	isa_context = kzalloc(sizeof(struct isa_driver_context),
+								GFP_KERNEL);
+	if (isa_context == NULL) {
+		dev_err(shrm->dev, "Failed to alloc memory\n");
+		return -ENOMEM;
+	}
+	shrm->isa_context = isa_context;
+	/*
+	 * L2 header of loopback device is 192(0xc0). As per the shrm
+	 * protocol the minor id of the deivce is mapped to the
+	 * L2 header.
+	 */
+	retval = alloc_chrdev_region(&dev_id, 0, MAX_L2_HEADERS, NAME);
+	major = MAJOR(dev_id);
+	dev_dbg(shrm->dev, " major %d\n", major);
+
+	cdev_init(&isa_context->cdev, &isa_fops);
+	isa_context->cdev.owner = THIS_MODULE;
+	retval = cdev_add(&isa_context->cdev, dev_id, MAX_L2_HEADERS);
+	if (retval) {
+		dev_err(shrm->dev, "Failed to add char device\n");
+		return retval;
+	}
+	/* create class and device */
+	isa_context->shrm_class = class_create(THIS_MODULE, NAME);
+	if (IS_ERR(isa_context->shrm_class)) {
+		dev_err(shrm->dev, "Error creating shrm class\n");
+		cdev_del(&isa_context->cdev);
+		retval = PTR_ERR(isa_context->shrm_class);
+		kfree(isa_context);
+		return retval;
+	}
+
+	for (no_dev = 0; no_dev < ISA_DEVICES; no_dev++) {
+		atomic_set(&isa_context->is_open[no_dev], 1);
+		device_create(isa_context->shrm_class, NULL,
+				MKDEV(MAJOR(dev_id),
+				map_dev[no_dev].l2_header), NULL,
+				map_dev[no_dev].name);
+	}
+
+	isa_context->isadev = kzalloc(sizeof
+				(struct isadev_context)*ISA_DEVICES,
+				GFP_KERNEL);
+	if (isa_context->isadev == NULL) {
+		dev_err(shrm->dev, "Failed to alloc memory\n");
+		goto alloc_fail;
+	}
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		isadev = &isa_context->isadev[no_dev];
+		isadev->device_id = no_dev;
+		retval = create_queue(&isadev->dl_queue,
+					isadev->device_id, shrm);
+
+		if (retval < 0) {
+			dev_err(shrm->dev, "create dl_queue failed\n");
+			delete_queue(&isadev->dl_queue);
+			kfree(isadev);
+			return retval;
+		}
+	}
+	mutex_init(&isa_context->tx_audio_mutex);
+	spin_lock_init(&isa_context->common_tx);
+	dev_dbg(shrm->dev, " SHRM Char Driver added\n");
+	return retval;
+alloc_fail:
+	class_destroy(isa_context->shrm_class);
+	cdev_del(&isa_context->cdev);
+	unregister_chrdev_region(dev_id, ISA_DEVICES);
+	kfree(isa_context);
+	return -ENOMEM;
+}
+
+void isa_exit(struct shrm_dev *shrm)
+{
+	int no_dev;
+	struct isadev_context *isadev;
+	struct isa_driver_context *isa_context = shrm->isa_context;
+	dev_t dev_id = MKDEV(major, 0);
+
+	for (no_dev = 0 ; no_dev < ISA_DEVICES ; no_dev++) {
+		device_destroy(isa_context->shrm_class,
+				MKDEV(MAJOR(dev_id),
+				map_dev[no_dev].l2_header));
+		isadev = &isa_context->isadev[no_dev];
+		delete_queue(&isadev->dl_queue);
+		kfree(isadev);
+	}
+	class_destroy(isa_context->shrm_class);
+	cdev_del(&isa_context->cdev);
+	unregister_chrdev_region(dev_id, ISA_DEVICES);
+	kfree(isa_context);
+	dev_dbg(shrm->dev, " SHRM Char Driver removed\n");
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_config.h b/drivers/modem_shm/u8500_shm/shrm_config.h
new file mode 100644
index 0000000..293f706
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_config.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_CONFIG_H
+#define __SHRM_CONFIG_H
+
+
+/*
+Note: modem need to define IPC as a non-cacheable area.
+In Cortex R4 MPU requires that base address of NC area is aligned on a
+region-sized boundary.On modem side, only 1 NC area can be defined, hence
+the whole IPC area must be defined as NC (at least).
+
+*/
+
+/* cache line size = 32bytes*/
+#define SHRM_CACHE_LINE 32
+#define SHRM_PTR_SIZE 4
+
+/* FIFO 0 address configuration */
+/* ---------------------------- */
+/* 128KB */
+#define SHRM_FIFO_0_SIZE (128*1024)
+
+
+/* == APE addresses == */
+#ifdef CONFIG_SHRM_V1_UPDATES_VERSION
+#define SHRM_IPC_BASE_AMCU 0x06F80000
+#define SHRM_IPC_END_AMCU 0x06FFFFFF
+#else
+#define SHRM_IPC_BASE_AMCU 0x06000000
+#define SHRM_IPC_END_AMCU 0x0607FFFF
+#endif
+
+/* offset pointers */
+#define SHRM_ACFIFO_0_WRITE_AMCU SHRM_IPC_BASE_AMCU
+#define SHRM_ACFIFO_0_READ_AMCU (SHRM_ACFIFO_0_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_0_WRITE_AMCU (SHRM_ACFIFO_0_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_READ_AMCU (SHRM_CAFIFO_0_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CA_MOD_RESET_STATUS_AMCU (SHRM_IPC_END_AMCU - 4)
+/* FIFO start */
+#define SHRM_ACFIFO_0_START_AMCU (SHRM_CAFIFO_0_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_START_AMCU (SHRM_ACFIFO_0_START_AMCU + SHRM_FIFO_0_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHRM_IPC_BASE_CMCU (SHRM_IPC_BASE_AMCU+0x08000000)
+/* offset pointers */
+#define SHRM_ACFIFO_0_WRITE_CMCU SHRM_IPC_BASE_CMCU
+#define SHRM_ACFIFO_0_READ_CMCU (SHRM_ACFIFO_0_WRITE_CMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_0_WRITE_CMCU (SHRM_ACFIFO_0_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_READ_CMCU (SHRM_CAFIFO_0_WRITE_CMCU + SHRM_PTR_SIZE)
+/* FIFO*/
+#define SHRM_ACFIFO_0_START_CMCU (SHRM_CAFIFO_0_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_0_START_CMCU (SHRM_ACFIFO_0_START_CMCU + SHRM_FIFO_0_SIZE)
+
+
+/* ADSP addresses*/
+#define SHRM_ACFIFO_0_START_ADSP 0x0
+#define SHRM_CAFIFO_0_START_ADSP 0x0
+#define SHRM_ACFIFO_0_WRITE_ADSP 0x0
+#define SHRM_ACFIFO_0_READ_ADSP 0x0
+#define SHRM_CAFIFO_0_WRITE_ADSP 0x0
+#define SHRM_CAFIFO_0_READ_ADSP 0x0
+
+/* FIFO 1 address configuration */
+/* ---------------------------- */
+
+
+/* FIFO 1 - 4K  */
+#define SHRM_FIFO_1_SIZE (4*1024)
+
+
+/* == APE addresses == */
+#define SHRM_ACFIFO_1_WRITE_AMCU (SHRM_CAFIFO_0_START_AMCU + SHRM_FIFO_0_SIZE)
+#define SHRM_ACFIFO_1_READ_AMCU (SHRM_ACFIFO_1_WRITE_AMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_1_WRITE_AMCU (SHRM_ACFIFO_1_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_READ_AMCU (SHRM_CAFIFO_1_WRITE_AMCU + SHRM_PTR_SIZE)
+/* FIFO*/
+#define SHRM_ACFIFO_1_START_AMCU (SHRM_CAFIFO_1_WRITE_AMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_START_AMCU (SHRM_ACFIFO_1_START_AMCU + SHRM_FIFO_1_SIZE)
+
+
+/* == CMT addresses ==*/
+#define SHRM_ACFIFO_1_WRITE_CMCU (SHRM_CAFIFO_0_START_CMCU + SHRM_FIFO_0_SIZE)
+#define SHRM_ACFIFO_1_READ_CMCU (SHRM_ACFIFO_1_WRITE_CMCU + SHRM_PTR_SIZE)
+#define SHRM_CAFIFO_1_WRITE_CMCU (SHRM_ACFIFO_1_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_READ_CMCU (SHRM_CAFIFO_1_WRITE_CMCU + SHRM_PTR_SIZE)
+/* FIFO1 start */
+#define SHRM_ACFIFO_1_START_CMCU (SHRM_CAFIFO_1_WRITE_CMCU + SHRM_CACHE_LINE)
+#define SHRM_CAFIFO_1_START_CMCU (SHRM_ACFIFO_1_START_CMCU + SHRM_FIFO_1_SIZE)
+
+
+/* ADSP addresses*/
+#define SHRM_ACFIFO_1_START_ADSP 0x0
+#define SHRM_CAFIFO_1_START_ADSP 0x0
+#define SHRM_ACFIFO_1_WRITE_ADSP 0x0
+#define SHRM_ACFIFO_1_READ_ADSP 0x0
+#define SHRM_CAFIFO_1_WRITE_ADSP 0x0
+#define SHRM_CAFIFO_1_READ_ADSP 0x0
+
+
+#define U8500_SHRM_FIFO_APE_COMMON_BASE  (SHRM_ACFIFO_0_START_AMCU)
+#define U8500_SHRM_FIFO_CMT_COMMON_BASE  (SHRM_CAFIFO_0_START_AMCU)
+#define U8500_SHRM_FIFO_APE_AUDIO_BASE   (SHRM_ACFIFO_1_START_AMCU)
+#define U8500_SHRM_FIFO_CMT_AUDIO_BASE   (SHRM_CAFIFO_1_START_AMCU)
+
+#endif /* __SHRM_CONFIG_H */
diff --git a/drivers/modem_shm/u8500_shm/shrm_driver.c b/drivers/modem_shm/u8500_shm/shrm_driver.c
new file mode 100644
index 0000000..19119d6
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_driver.c
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+#include <linux/skbuff.h>
+#ifdef CONFIG_HIGH_RES_TIMERS
+#include <linux/hrtimer.h>
+static struct hrtimer timer;
+#endif
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_net.h"
+#include "shrm.h"
+#include "shrm_ioctl.h"
+
+/* debug functionality */
+#define ISA_DEBUG 0
+
+/* count for no of msg to be check befor suspend */
+#define CHK_SLP_MSG_CNT 3
+
+#define PHONET_TASKLET
+#define MAX_RCV_LEN	2048
+
+static void do_phonet_rcv_tasklet(unsigned long unused);
+struct tasklet_struct phonet_rcv_tasklet;
+
+/**
+ * audio_receive() - Receive audio channel completion callback
+ * @shrm:	pointer to shrm device information structure
+ * @data:	message pointer
+ * @n_bytes:	message size
+ * @l2_header:	L2 header/device ID 2->audio, 5->audio_loopback
+ *
+ * This fucntion is called from the audio receive handler. Copies the audio
+ * message from the FIFO to the AUDIO queue. The message is later copied from
+ * this queue to the user buffer through the char or net interface read
+ * operation.
+ */
+static int audio_receive(struct shrm_dev *shrm, void *data,
+					u32 n_bytes, u8 l2_header)
+{
+	u32 size = 0;
+	int ret = 0;
+	int idx;
+	u8 *psrc;
+	struct message_queue *q;
+	struct isadev_context *audiodev;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	idx = shrm_get_cdev_index(l2_header);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		return idx;
+	}
+	audiodev = &shrm->isa_context->isadev[idx];
+	q = &audiodev->dl_queue;
+	spin_lock(&q->update_lock);
+	/* Memcopy RX data first */
+	if ((q->writeptr+n_bytes) >= q->size) {
+		psrc = (u8 *)data;
+		size = (q->size-q->writeptr);
+		/* Copy First Part of msg */
+		memcpy((q->fifo_base+q->writeptr), psrc, size);
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		memcpy(q->fifo_base, psrc, (n_bytes-size));
+	} else {
+		memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+	}
+	ret = add_msg_to_queue(q, n_bytes);
+	spin_unlock(&q->update_lock);
+	if (ret < 0)
+		dev_err(shrm->dev, "Adding a msg to message queue failed");
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * common_receive() - Receive common channel completion callback
+ * @shrm:	pointer to the shrm device information structure
+ * @data:	message pointer
+ * @n_bytes:	message size
+ * @l2_header:	L2 header / device ID
+ *
+ * This function is called from the receive handler to copy the respective
+ * ISI, RPC, SECURITY message to its respective queue. The message is then
+ * copied from queue to the user buffer on char net interface read operation.
+ */
+static int common_receive(struct shrm_dev *shrm, void *data,
+					u32 n_bytes, u8 l2_header)
+{
+	u32 size = 0;
+	int ret = 0;
+	int idx;
+	u8 *psrc;
+	struct message_queue *q;
+	struct isadev_context *isa_dev;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	idx = shrm_get_cdev_index(l2_header);
+	if (idx < 0) {
+		dev_err(shrm->dev, "failed to get index\n");
+		return idx;
+	}
+	isa_dev = &shrm->isa_context->isadev[idx];
+	q = &isa_dev->dl_queue;
+	spin_lock(&q->update_lock);
+	/* Memcopy RX data first */
+	if ((q->writeptr+n_bytes) >= q->size) {
+		dev_dbg(shrm->dev, "Inside Loop Back\n");
+		psrc = (u8 *)data;
+		size = (q->size-q->writeptr);
+		/* Copy First Part of msg */
+		memcpy((q->fifo_base+q->writeptr), psrc, size);
+		psrc += size;
+		/* Copy Second Part of msg at the top of fifo */
+		memcpy(q->fifo_base, psrc, (n_bytes-size));
+	} else {
+		memcpy((q->fifo_base+q->writeptr), data, n_bytes);
+	}
+	ret = add_msg_to_queue(q, n_bytes);
+	spin_unlock(&q->update_lock);
+	if (ret < 0) {
+		dev_err(shrm->dev, "Adding a msg to message queue failed");
+		return ret;
+	}
+
+
+	if (l2_header == ISI_MESSAGING) {
+		if (shrm->netdev_flag_up) {
+			dev_dbg(shrm->dev,
+				"scheduling the phonet tasklet from %s!\n",
+				__func__);
+			tasklet_schedule(&phonet_rcv_tasklet);
+		}
+		dev_dbg(shrm->dev,
+				"Out of phonet tasklet %s!!!\n", __func__);
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return ret;
+}
+
+/**
+ * rx_common_l2msg_handler() - common channel receive handler
+ * @l2_header:		L2 header
+ * @msg:		pointer to the receive buffer
+ * @length:		length of the msg to read
+ * @shrm:		pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_common_l2msg_handler(u8 l2_header,
+				 void *msg, u32 length,
+				 struct shrm_dev *shrm)
+{
+	int ret = 0;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	ret = common_receive(shrm, msg, length, l2_header);
+	if (ret < 0)
+		dev_err(shrm->dev,
+			"common receive with l2 header %d failed\n", l2_header);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * rx_audio_l2msg_handler() - audio channel receive handler
+ * @l2_header:		L2 header
+ * @msg:		pointer to the receive buffer
+ * @length:		length of the msg to read
+ * @shrm:		pointer to shrm device information structure
+ *
+ * This function is called to receive the message from CaMsgPendingNotification
+ * interrupt handler.
+ */
+static void rx_audio_l2msg_handler(u8 l2_header,
+				void *msg, u32 length,
+				struct shrm_dev *shrm)
+{
+	int ret = 0;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	ret = audio_receive(shrm, msg, length, l2_header);
+	if (ret < 0)
+		dev_err(shrm->dev, "audio receive failed\n");
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int __init shrm_initialise_irq(struct shrm_dev *shrm)
+{
+	int err = 0;
+
+	err  = shrm_protocol_init(shrm,
+			rx_common_l2msg_handler, rx_audio_l2msg_handler);
+	if (err < 0) {
+		dev_err(shrm->dev, "SHRM Protocol Init Failure\n");
+		return err;
+	}
+
+	err = request_irq(shrm->ca_wake_irq,
+			ca_wake_irq_handler, IRQF_TRIGGER_RISING,
+				 "ca_wake-up", shrm);
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"Unable to allocate shrm tx interrupt line\n");
+		free_irq(shrm->ca_wake_irq, shrm);
+		return err;
+	}
+
+	err = request_irq(shrm->ac_read_notif_0_irq,
+		ac_read_notif_0_irq_handler, 0,
+		"ac_read_notif_0", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ac_read_notif_0_irq interrupt line\n");
+		goto irq_err1;
+	}
+
+	err = request_irq(shrm->ac_read_notif_1_irq,
+		ac_read_notif_1_irq_handler, 0,
+		"ac_read_notif_1", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ac_read_notif_1_irq interrupt line\n");
+		goto irq_err2;
+	}
+
+	err = request_irq(shrm->ca_msg_pending_notif_0_irq,
+		 ca_msg_pending_notif_0_irq_handler, 0,
+		"ca_msg_pending_notif_0", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+				"error ca_msg_pending_notif_0_irq line\n");
+		goto irq_err3;
+	}
+
+	err = request_irq(shrm->ca_msg_pending_notif_1_irq,
+		 ca_msg_pending_notif_1_irq_handler, 0,
+		"ca_msg_pending_notif_1", shrm);
+
+	if (err < 0) {
+		dev_err(shrm->dev,
+			"error ca_msg_pending_notif_1_irq interrupt line\n");
+		goto irq_err4;
+	}
+	return err;
+irq_err4:
+	free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+irq_err3:
+	free_irq(shrm->ac_read_notif_1_irq, shrm);
+irq_err2:
+	free_irq(shrm->ac_read_notif_0_irq, shrm);
+irq_err1:
+	free_irq(shrm->ca_wake_irq, shrm);
+	return err;
+}
+
+static void free_shrm_irq(struct shrm_dev *shrm)
+{
+	free_irq(shrm->ca_wake_irq, shrm);
+	free_irq(shrm->ac_read_notif_0_irq, shrm);
+	free_irq(shrm->ac_read_notif_1_irq, shrm);
+	free_irq(shrm->ca_msg_pending_notif_0_irq, shrm);
+	free_irq(shrm->ca_msg_pending_notif_1_irq, shrm);
+}
+
+
+
+#ifdef CONFIG_HIGH_RES_TIMERS
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+	return HRTIMER_NORESTART;
+}
+#endif
+
+void do_phonet_rcv_tasklet(unsigned long unused)
+{
+	ssize_t ret;
+	struct shrm_dev *shrm = (struct shrm_dev *)unused;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	for (;;) {
+		ret = shrm_net_receive(shrm->ndev);
+		if (ret == 0) {
+			dev_dbg(shrm->dev, "len is zero, queue empty\n");
+			break;
+		}
+		if (ret < 0) {
+			dev_err(shrm->dev, "len < 0 !!! error!!!\n");
+			break;
+		}
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static int shrm_probe(struct platform_device *pdev)
+{
+	int err = 0;
+	struct resource *res;
+	struct shrm_dev *shrm = NULL;
+
+	shrm = kzalloc(sizeof(struct shrm_dev), GFP_KERNEL);
+	if (shrm == NULL) {
+		dev_err(&pdev->dev,
+			"Could not allocate memory for struct shrm_dev\n");
+		return -ENOMEM;
+	}
+
+	shrm->dev = &pdev->dev;
+	shrm->modem = modem_get(shrm->dev, "u8500-shrm-modem");
+	if (shrm->modem == NULL) {
+		dev_err(shrm->dev, " Could not retrieve the modem.\n");
+		err = -ENODEV;
+		goto rollback_intr;
+	}
+
+	/* initialise the SHRM */
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(shrm->dev,
+				"Unable to map Ca Wake up interrupt\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_wake_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map APE_Read_notif_common IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ac_read_notif_0_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map APE_Read_notif_audio IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ac_read_notif_1_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map Cmt_msg_pending_notif_common IRQbase\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_msg_pending_notif_0_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 4);
+
+	if (!res) {
+		dev_err(shrm->dev,
+			"Unable to map Cmt_msg_pending_notif_audio IRQ base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ca_msg_pending_notif_1_irq = res->start;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res) {
+		dev_err(shrm->dev,
+				"Could not get SHRM IO memory information\n");
+		err = -ENODEV;
+		goto rollback_intr;
+	}
+	shrm->intr_base = (void __iomem *)ioremap_nocache(res->start,
+					res->end - res->start + 1);
+	if (!(shrm->intr_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_intr;
+	}
+	shrm->ape_common_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_APE_COMMON_BASE;
+	shrm->ape_common_fifo_base =
+		(void __iomem *)ioremap_nocache(
+					U8500_SHRM_FIFO_APE_COMMON_BASE,
+					SHRM_FIFO_0_SIZE);
+	shrm->ape_common_fifo_size = (SHRM_FIFO_0_SIZE)/4;
+
+	if (!(shrm->ape_common_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ape_common_fifo_base;
+	}
+	shrm->cmt_common_fifo_base_phy =
+		(u32 *)U8500_SHRM_FIFO_CMT_COMMON_BASE;
+	shrm->cmt_common_fifo_base =
+		(void __iomem *)ioremap_nocache(
+			U8500_SHRM_FIFO_CMT_COMMON_BASE, SHRM_FIFO_0_SIZE);
+	shrm->cmt_common_fifo_size = (SHRM_FIFO_0_SIZE)/4;
+
+	if (!(shrm->cmt_common_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_cmt_common_fifo_base;
+	}
+	shrm->ape_audio_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_APE_AUDIO_BASE;
+	shrm->ape_audio_fifo_base =
+		(void __iomem *)ioremap_nocache(U8500_SHRM_FIFO_APE_AUDIO_BASE,
+							SHRM_FIFO_1_SIZE);
+	shrm->ape_audio_fifo_size = (SHRM_FIFO_1_SIZE)/4;
+
+	if (!(shrm->ape_audio_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ape_audio_fifo_base;
+	}
+	shrm->cmt_audio_fifo_base_phy =
+			(u32 *)U8500_SHRM_FIFO_CMT_AUDIO_BASE;
+	shrm->cmt_audio_fifo_base =
+		(void __iomem *)ioremap_nocache(U8500_SHRM_FIFO_CMT_AUDIO_BASE,
+							SHRM_FIFO_1_SIZE);
+	shrm->cmt_audio_fifo_size = (SHRM_FIFO_1_SIZE)/4;
+
+	if (!(shrm->cmt_audio_fifo_base)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_cmt_audio_fifo_base;
+	}
+	shrm->ac_common_shared_wptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_0_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_common_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_ac_common_shared_wptr;
+	}
+	shrm->ac_common_shared_rptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_0_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_common_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_common_shared_wptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_0_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_common_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_common_shared_rptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_0_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_common_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ac_audio_shared_wptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_1_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_audio_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ac_audio_shared_rptr =
+		(void __iomem *)ioremap(SHRM_ACFIFO_1_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ac_audio_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_audio_shared_wptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_1_WRITE_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_audio_shared_wptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_audio_shared_rptr =
+		(void __iomem *)ioremap(SHRM_CAFIFO_1_READ_AMCU, SHRM_PTR_SIZE);
+
+	if (!(shrm->ca_audio_shared_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+	shrm->ca_reset_status_rptr =
+		(void __iomem *)ioremap(SHRM_CA_MOD_RESET_STATUS_AMCU, SHRM_PTR_SIZE);
+	if (!(shrm->ca_reset_status_rptr)) {
+		dev_err(shrm->dev, "Unable to map register base\n");
+		err = -EBUSY;
+		goto rollback_map;
+	}
+
+	if (isa_init(shrm) != 0) {
+		dev_err(shrm->dev, "Driver Initialization Error\n");
+		err = -EBUSY;
+	}
+	/* install handlers and tasklets */
+	if (shrm_initialise_irq(shrm)) {
+		dev_err(shrm->dev,
+				"shrm error in interrupt registration\n");
+		goto rollback_irq;
+	}
+#ifdef CONFIG_HIGH_RES_TIMERS
+	hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer.function = callback;
+	hrtimer_start(&timer, ktime_set(0, 2*NSEC_PER_MSEC), HRTIMER_MODE_REL);
+#endif
+	err = shrm_register_netdev(shrm);
+	if (err < 0)
+		goto rollback_irq;
+
+	tasklet_init(&phonet_rcv_tasklet, do_phonet_rcv_tasklet, 0);
+	phonet_rcv_tasklet.data = (unsigned long)shrm;
+
+	platform_set_drvdata(pdev, shrm);
+
+	return err;
+rollback_irq:
+	free_shrm_irq(shrm);
+rollback_map:
+	iounmap(shrm->ac_common_shared_wptr);
+	iounmap(shrm->ac_common_shared_rptr);
+	iounmap(shrm->ca_common_shared_wptr);
+	iounmap(shrm->ca_common_shared_rptr);
+	iounmap(shrm->ac_audio_shared_wptr);
+	iounmap(shrm->ac_audio_shared_rptr);
+	iounmap(shrm->ca_audio_shared_wptr);
+	iounmap(shrm->ca_audio_shared_rptr);
+rollback_ac_common_shared_wptr:
+	iounmap(shrm->cmt_audio_fifo_base);
+rollback_cmt_audio_fifo_base:
+	iounmap(shrm->ape_audio_fifo_base);
+rollback_ape_audio_fifo_base:
+	iounmap(shrm->cmt_common_fifo_base);
+rollback_cmt_common_fifo_base:
+	iounmap(shrm->ape_common_fifo_base);
+rollback_ape_common_fifo_base:
+	iounmap(shrm->intr_base);
+rollback_intr:
+	kfree(shrm);
+	return err;
+}
+
+static int __exit shrm_remove(struct platform_device *pdev)
+{
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+
+	free_shrm_irq(shrm);
+	iounmap(shrm->intr_base);
+	iounmap(shrm->ape_common_fifo_base);
+	iounmap(shrm->cmt_common_fifo_base);
+	iounmap(shrm->ape_audio_fifo_base);
+	iounmap(shrm->cmt_audio_fifo_base);
+	iounmap(shrm->ac_common_shared_wptr);
+	iounmap(shrm->ac_common_shared_rptr);
+	iounmap(shrm->ca_common_shared_wptr);
+	iounmap(shrm->ca_common_shared_rptr);
+	iounmap(shrm->ac_audio_shared_wptr);
+	iounmap(shrm->ac_audio_shared_rptr);
+	iounmap(shrm->ca_audio_shared_wptr);
+	iounmap(shrm->ca_audio_shared_rptr);
+	shrm_unregister_netdev(shrm);
+	isa_exit(shrm);
+	kfree(shrm);
+
+	return 0;
+}
+
+static int u8500_shrm_chk_unread_msg(struct shrm_dev *shrm)
+{
+	struct message_queue *q;
+	struct isadev_context *isa_dev;
+	int idx;
+	u8 cnt;
+
+	struct sleep_msg_list {
+		u8 l2_header;
+		char *name;
+	};
+
+	/* list of messages or l2 header to be check before going susped */
+	struct sleep_msg_list slp_msg[] = {
+		{RPC_MESSAGING, "RPC"},
+		{SECURITY_MESSAGING, "Security"},
+		{ISI_MESSAGING, "ISI"},
+	};
+
+	for (cnt = 0; cnt < CHK_SLP_MSG_CNT; cnt++) {
+		idx = shrm_get_cdev_index(slp_msg[cnt].l2_header);
+		isa_dev = &shrm->isa_context->isadev[idx];
+		q = &isa_dev->dl_queue;
+		if (!list_empty(&q->msg_list)) {
+
+			if (atomic_dec_and_test(&shrm->isa_context->is_open[idx])) {
+				atomic_inc(&shrm->isa_context->is_open[idx]);
+				dev_info(shrm->dev, "%s device not opened yet, flush queue\n",
+					slp_msg[cnt].name);
+				shrm_char_reset_queues(shrm);
+			} else {
+				atomic_inc(&shrm->isa_context->is_open[idx]);
+				dev_info(shrm->dev, "Some %s msg unread = %d\n",
+					slp_msg[cnt].name, get_size_of_new_msg(q));
+				return -EBUSY;
+			}
+		}
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/**
+ * u8500_shrm_suspend() - This routine puts the SHRM in to sustend state.
+ * @dev:	pointer to device structure.
+ *
+ * This routine checks the current ongoing communication with Modem by
+ * examining the ca_wake state and prevents suspend if modem communication
+ * is on-going.
+ * If ca_wake = 1 (high), modem comm. is on-going; don't suspend
+ * If ca_wake = 0 (low), no comm. with modem on-going.Allow suspend
+ */
+int u8500_shrm_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+	int err;
+
+	dev_dbg(&pdev->dev, "%s called...\n", __func__);
+	dev_dbg(&pdev->dev, "ca_wake_req_state = %x\n",
+						get_ca_wake_req_state());
+
+	/*
+	* Is there are any messages unread in the RPC or Security queue,
+	* dont suspend as these are real time and modem expects response
+	* within 1sec else will end up in a crash. If userspace doesn't
+	* open the device, then will flush the queue and allow device go to suspend
+	*/
+
+	if (u8500_shrm_chk_unread_msg(shrm))
+		return -EBUSY;
+
+	/* if ca_wake_req is high, prevent system suspend */
+	if (!get_ca_wake_req_state()) {
+		err = shrm_suspend_netdev(shrm->ndev);
+		return err;
+	} else
+		return -EBUSY;
+}
+
+/**
+ * u8500_shrm_resume() - This routine resumes the SHRM from suspend state.
+ * @dev:	pointer to device structure
+ *
+ * This routine restore back the current state of the SHRM
+ */
+int u8500_shrm_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct shrm_dev *shrm = platform_get_drvdata(pdev);
+	int err;
+
+	dev_dbg(&pdev->dev, "%s called...\n", __func__);
+	err = shrm_resume_netdev(shrm->ndev);
+
+	return err;
+}
+
+static const struct dev_pm_ops shrm_dev_pm_ops = {
+	.suspend_noirq = u8500_shrm_suspend,
+	.resume_noirq = u8500_shrm_resume,
+};
+#endif
+
+static struct platform_driver shrm_driver = {
+	.remove = __exit_p(shrm_remove),
+	.driver = {
+		.name = "u8500_shrm",
+		.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+		.pm = &shrm_dev_pm_ops,
+#endif
+	},
+};
+
+static int __init shrm_driver_init(void)
+{
+	return platform_driver_probe(&shrm_driver, shrm_probe);
+}
+
+static void __exit shrm_driver_exit(void)
+{
+	platform_driver_unregister(&shrm_driver);
+}
+
+module_init(shrm_driver_init);
+module_exit(shrm_driver_exit);
+
+MODULE_AUTHOR("Arun Murthy, Kumar Sanghvi");
+MODULE_DESCRIPTION("Shared Memory Modem Driver Interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/modem_shm/u8500_shm/shrm_driver.h b/drivers/modem_shm/u8500_shm/shrm_driver.h
new file mode 100644
index 0000000..f703ee5
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_driver.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_DRIVER_H__
+#define __SHRM_DRIVER_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/modem_shm/modem_client.h>
+
+#include "shrm.h"
+
+#define ISA_DEVICES 8
+
+#define BOOT_INIT  (0)
+#define BOOT_INFO_SYNC  (1)
+#define BOOT_DONE  (2)
+#define BOOT_UNKNOWN (3)
+
+/**
+ * struct shrm_dev - shrm device information
+ * @ca_wake_irq:		CMT wake interrupt number
+ * @ac_read_notif_0_irq:	ape-cmt common channel read notify interrupt
+ * @ac_read_notif_1_irq:	ape-cmt audio channel read notify interrupt
+ * @ca_msg_pending_notif_0_irq:	cmt-ape common channel msg pending interrupt
+ * @ca_msg_pending_notif_1_irq:	cmt-ape audio channel msg pending interrupt
+ * @intr_base:			interrupt base register address
+ * @ape_common_fifo_base:	ape side common channel fifo base addr
+ * @ape_audio_fifo_base:	ape side audio channel fifo base addr
+ * @cmt_common_fifo_base:	cmt side common channel fifo base addr
+ * @cmt_audio_fifo_base:	cmt side audio channel fifo base addr
+ * @ape_common_fifo_base_phy:	physical addr of ape common fifo
+ * @ape_audio_fifo_base_phy:	physical addr of ape audio fifo
+ * @cmt_common_fifo_base_phy:	physical addr of cmt common fifo
+ * @cmt_audio_fifo_base_phy:	physical addr of cmt audio fifo
+ * @ape_common_fifo_size:	ape side common channel fifo size
+ * @ape_audio_fifo_size:	ape side audio channel fifo size
+ * @cmt_common_fifo_size:	cmt side common channel fifo size
+ * @cmt_audio_fifo_size:	cmt side audio channel fifo size
+ * @netdev_flag_up:		flag to indicate up/down of netwok device
+ * @msr_flag:			flag to check on-going MSR sequence
+ * @ac_common_shared_wptr:	ape-cmt common channel write pointer
+ * @ac_common_shared_rptr:	ape-cmt common channel read pointer
+ * @ca_common_shared_wptr:	cmt-ape common channel write pointer
+ * @ca_common_shared_rptr:	cmt-ape common channel read pointer
+ * @ac_audio_shared_wptr:	ape-cmt audio channel write pointer
+ * @ac_audio_shared_rptr:	ape-cmt audio channel read pointer
+ * @ca_audio_shared_wptr:	cmt-ape audio channel write pointer
+ * @ca_audio_shared_rptr:	cmt-ape audio channel read pointer
+ * @ca_reset_status_rptr:	cmt-ape modem reset status pointer
+ * @dev:			pointer to the driver device
+ * @ndev:			pointer to the network device structure
+ * @modem:			poiner to struct modem
+ * @isa_context:		pointer to t_isa_driver_sontext dtructure
+ * @shrm_common_ch_wr_kw:	kthread worker for writing to common channel
+ * @shrm_common_ch_wr_kw_task:	task for writing to common channel
+ * @shrm_audio_ch_wr_kw:		kthread worker for writing to audio channel
+ * @shrm_audio_ch_wr_kw_task:	task for writing to audio channel
+ * @shrm_ac_wake_kw:		kthread worker for receiving ape-cmt wake requests
+ * @shrm_ac_wake_kw_task:	task for receiving ape-cmt wake requests
+ * @shrm_ca_wake_kw:		kthread worker for receiving cmt-ape wake requests
+ * @shrm_ca_wake_kw_task:	task for receiving cmt-ape wake requests
+ * @shrm_ac_sleep_kw:		kthread worker for recieving ape-cmt sleep requests
+ * @shrm_ac_sleep_kw_task:	task for recieving ape-cmt sleep requests
+ * @shrm_mod_stuck_kw:		kthread worker to reset the modem
+ * @shrm_mod_stuck_kw_task:	task for sending modem reset request
+ * @send_ac_msg_pend_notify_0:	work for handling pending message on common
+ * channel
+ * @send_ac_msg_pend_notify_1:	work for handling pending message on audio
+ * channel
+ * @shrm_ac_wake_req:		work to send ape-cmt wake request
+ * @shrm_ca_wake_req:		work to send cmt-ape wake request
+ * @shrm_ca_sleep_req:		work to send cmt-ape sleep request
+ * @shrm_ac_sleep_req:		work to send ape-cmt sleep request
+ * @shrm_mod_reset_req:		work to send a reset request to modem
+ * @shrm_print_dbg_info:		work function to print all prcmu/abb registers
+ */
+struct shrm_dev {
+	u8 ca_wake_irq;
+	u8 ac_read_notif_0_irq;
+	u8 ac_read_notif_1_irq;
+	u8 ca_msg_pending_notif_0_irq;
+	u8 ca_msg_pending_notif_1_irq;
+	void __iomem *intr_base;
+	void __iomem *ape_common_fifo_base;
+	void __iomem *ape_audio_fifo_base;
+	void __iomem *cmt_common_fifo_base;
+	void __iomem *cmt_audio_fifo_base;
+
+	u32 *ape_common_fifo_base_phy;
+	u32 *ape_audio_fifo_base_phy;
+	u32 *cmt_common_fifo_base_phy;
+	u32 *cmt_audio_fifo_base_phy;
+
+	int ape_common_fifo_size;
+	int ape_audio_fifo_size;
+	int cmt_common_fifo_size;
+	int cmt_audio_fifo_size;
+	int netdev_flag_up;
+	int msr_flag;
+
+	void __iomem *ac_common_shared_wptr;
+	void __iomem *ac_common_shared_rptr;
+	void __iomem *ca_common_shared_wptr;
+	void __iomem *ca_common_shared_rptr;
+
+	void __iomem *ac_audio_shared_wptr;
+	void __iomem *ac_audio_shared_rptr;
+	void __iomem *ca_audio_shared_wptr;
+	void __iomem *ca_audio_shared_rptr;
+
+	void __iomem *ca_reset_status_rptr;
+
+	struct device *dev;
+	struct net_device *ndev;
+	struct modem *modem;
+	struct isa_driver_context *isa_context;
+	struct kthread_worker shrm_common_ch_wr_kw;
+	struct task_struct *shrm_common_ch_wr_kw_task;
+	struct kthread_worker shrm_audio_ch_wr_kw;
+	struct task_struct *shrm_audio_ch_wr_kw_task;
+	struct kthread_worker shrm_ac_wake_kw;
+	struct task_struct *shrm_ac_wake_kw_task;
+	struct kthread_worker shrm_ca_wake_kw;
+	struct task_struct *shrm_ca_wake_kw_task;
+	struct kthread_worker shrm_ac_sleep_kw;
+	struct task_struct *shrm_ac_sleep_kw_task;
+	struct kthread_worker shrm_mod_stuck_kw;
+	struct task_struct *shrm_mod_stuck_kw_task;
+	struct kthread_work send_ac_msg_pend_notify_0;
+	struct kthread_work send_ac_msg_pend_notify_1;
+	struct kthread_work shrm_ac_wake_req;
+	struct kthread_work shrm_ca_wake_req;
+	struct kthread_work shrm_ca_sleep_req;
+	struct kthread_work shrm_ac_sleep_req;
+	struct kthread_work shrm_mod_reset_req;
+	struct kthread_work shrm_print_dbg_info;
+};
+
+/**
+ * struct queue_element - information to add an element to queue
+ * @entry:	list entry
+ * @offset:	message offset
+ * @size:	message size
+ * @no:		total number of messages
+ */
+struct queue_element {
+	struct list_head entry;
+	u32 offset;
+	u32 size;
+	u32 no;
+};
+
+/**
+ * struct message_queue - ISI, RPC, AUDIO, SECURITY message queue information
+ * @fifo_base:		pointer to the respective fifo base
+ * @size:		size of the data to be read
+ * @readptr:		fifo read pointer
+ * @writeptr:		fifo write pointer
+ * @no:			total number of messages
+ * @update_lock:	spinlock for protecting the queue read operation
+ * @q_rp:		queue write pointer
+ * @wq_readable:	wait queue head
+ * @msg_list:		message list
+ * @shrm:		pointer to shrm device information structure
+ */
+struct message_queue {
+      u8 *fifo_base;
+      u32 size;
+      u32 readptr;
+      u32 writeptr;
+      u32 no;
+      spinlock_t update_lock;
+      atomic_t q_rp;
+      wait_queue_head_t wq_readable;
+      struct list_head msg_list;
+      struct shrm_dev *shrm;
+};
+
+/**
+ * struct isadev_context - shrm char interface context
+ * @dl_queue:	structre to store the queue related info
+ * @device_id:	message id(ISI, RPC, AUDIO, SECURITY)
+ * @addr:	device addresses.
+ */
+struct isadev_context {
+	struct message_queue dl_queue;
+	u8 device_id;
+	void *addr;
+};
+
+/**
+ * struct isa_driver_context - shrm char interface device information
+ * @is_open:		flag to check the usage of queue
+ * @isadev:		pointer to struct t_isadev_context
+ * @common_tx:		spinlock for protecting common channel
+ * @tx_audio_mutex:	mutex for protecting audio channel
+ * @cdev:		character device structre
+ * @shrm_class:		pointer to the class structure
+ */
+struct isa_driver_context {
+	atomic_t is_open[ISA_DEVICES];
+	struct isadev_context *isadev;
+	spinlock_t common_tx;
+	struct mutex tx_audio_mutex;
+	struct cdev cdev;
+	struct class *shrm_class;
+};
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_fifo.c b/drivers/modem_shm/u8500_shm/shrm_fifo.c
new file mode 100644
index 0000000..f6dc069
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_fifo.c
@@ -0,0 +1,838 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include "shrm.h"
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_net.h"
+
+#define L1_BOOT_INFO_REQ	1
+#define L1_BOOT_INFO_RESP	2
+#define L1_NORMAL_MSG		3
+#define L1_HEADER_MASK		28
+#define L1_MAPID_MASK		0xF0000000
+#define CONFIG_OFFSET		8
+#define COUNTER_OFFSET		20
+#define L2_HEADER_SIZE		4
+#define L2_HEADER_OFFSET	24
+#define MASK_0_15_BIT		0xFF
+#define MASK_16_31_BIT		0xFF00
+#define MASK_16_27_BIT		0xFFF0000
+#define MASK_0_39_BIT		0xFFFFF
+#define MASK_40_55_BIT		0xFF00000
+#define MASK_8_16_BIT           0x0000FF00
+#define MSG_LEN_OFFSET          16
+#define SHRM_VER                2
+#define ca_ist_inactivity_timer 25 /*25ms */
+#define ca_csc_inactivity_timer 25 /*25ms */
+
+static u8 msg_audio_counter;
+static u8 msg_common_counter;
+
+static struct fifo_write_params ape_shrm_fifo_0;
+static struct fifo_write_params ape_shrm_fifo_1;
+static struct fifo_read_params cmt_shrm_fifo_0;
+static struct fifo_read_params cmt_shrm_fifo_1;
+
+
+static u8 cmt_read_notif_0_send;
+static u8 cmt_read_notif_1_send;
+
+void shrm_fifo_init(struct shrm_dev *shrm)
+{
+	ape_shrm_fifo_0.writer_local_wptr	= 0;
+	ape_shrm_fifo_0.writer_local_rptr	= 0;
+	*((u32 *)shrm->ac_common_shared_wptr) = 0;
+	*((u32 *)shrm->ac_common_shared_rptr) = 0;
+	ape_shrm_fifo_0.shared_wptr		= 0;
+	ape_shrm_fifo_0.shared_rptr		= 0;
+	ape_shrm_fifo_0.availablesize = shrm->ape_common_fifo_size;
+	ape_shrm_fifo_0.end_addr_fifo    = shrm->ape_common_fifo_size;
+	ape_shrm_fifo_0.fifo_virtual_addr = shrm->ape_common_fifo_base;
+	spin_lock_init(&ape_shrm_fifo_0.fifo_update_lock);
+
+
+	cmt_shrm_fifo_0.reader_local_rptr	= 0;
+	cmt_shrm_fifo_0.reader_local_wptr	= 0;
+	cmt_shrm_fifo_0.shared_wptr	=
+			*((u32 *)shrm->ca_common_shared_wptr);
+	cmt_shrm_fifo_0.shared_rptr	=
+			*((u32 *)shrm->ca_common_shared_rptr);
+	cmt_shrm_fifo_0.availablesize	= shrm->cmt_common_fifo_size;
+	cmt_shrm_fifo_0.end_addr_fifo	= shrm->cmt_common_fifo_size;
+	cmt_shrm_fifo_0.fifo_virtual_addr = shrm->cmt_common_fifo_base;
+
+	ape_shrm_fifo_1.writer_local_wptr	= 0;
+	ape_shrm_fifo_1.writer_local_rptr	= 0;
+	ape_shrm_fifo_1.shared_wptr		= 0;
+	ape_shrm_fifo_1.shared_rptr		= 0;
+	*((u32 *)shrm->ac_audio_shared_wptr) = 0;
+	*((u32 *)shrm->ac_audio_shared_rptr) = 0;
+	ape_shrm_fifo_1.availablesize = shrm->ape_audio_fifo_size;
+	ape_shrm_fifo_1.end_addr_fifo    = shrm->ape_audio_fifo_size;
+	ape_shrm_fifo_1.fifo_virtual_addr = shrm->ape_audio_fifo_base;
+	spin_lock_init(&ape_shrm_fifo_1.fifo_update_lock);
+
+	cmt_shrm_fifo_1.reader_local_rptr	= 0;
+	cmt_shrm_fifo_1.reader_local_wptr	= 0;
+	cmt_shrm_fifo_1.shared_wptr		=
+			*((u32 *)shrm->ca_audio_shared_wptr);
+	cmt_shrm_fifo_1.shared_rptr		=
+			*((u32 *)shrm->ca_audio_shared_rptr);
+	cmt_shrm_fifo_1.availablesize	= shrm->cmt_audio_fifo_size;
+	cmt_shrm_fifo_1.end_addr_fifo	= shrm->cmt_audio_fifo_size;
+	cmt_shrm_fifo_1.fifo_virtual_addr = shrm->cmt_audio_fifo_base;
+	msg_audio_counter = 0;
+	msg_common_counter = 0;
+}
+
+u8 read_boot_info_req(struct shrm_dev *shrm,
+				u32 *config,
+				u32 *version)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+	u32 *msg;
+	u32 header = 0;
+	u8 msgtype;
+
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->reader_local_rptr + fifo->fifo_virtual_addr);
+	header = *msg;
+	msgtype = (header & L1_MAPID_MASK) >> L1_MSG_MAPID_OFFSET;
+	if (msgtype != L1_BOOT_INFO_REQ) {
+		dev_err(shrm->dev, "Read_Boot_Info_Req Fatal ERROR\n");
+		dev_err(shrm->dev, "Received msgtype is %d\n", msgtype);
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+		return 0;
+	}
+	*config = (header >> CONFIG_OFFSET) & MASK_0_15_BIT;
+	*version = header & MASK_0_15_BIT;
+	fifo->reader_local_rptr += 1;
+
+	return 1;
+}
+
+void write_boot_info_resp(struct shrm_dev *shrm, u32 config,
+							u32 version)
+{
+	struct fifo_write_params *fifo = &ape_shrm_fifo_0;
+	u32 *msg;
+	u8 msg_length;
+	version = SHRM_VER;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->writer_local_wptr+fifo->fifo_virtual_addr);
+	if (version < 1)	{
+		*msg = ((L1_BOOT_INFO_RESP << L1_MSG_MAPID_OFFSET) |
+				((config << CONFIG_OFFSET) & MASK_16_31_BIT)
+				| (version & MASK_0_15_BIT));
+		msg_length = 1;
+	} else {
+		*msg = ((L1_BOOT_INFO_RESP << L1_MSG_MAPID_OFFSET) |
+			((0x8 << MSG_LEN_OFFSET) & MASK_16_27_BIT) |
+			((config << CONFIG_OFFSET) & MASK_8_16_BIT)|
+			version);
+		msg++;
+		*msg = ca_ist_inactivity_timer;
+		msg++;
+		*msg = ca_csc_inactivity_timer;
+		msg_length = L1_NORMAL_MSG;
+	}
+	fifo->writer_local_wptr += msg_length;
+	fifo->availablesize -= msg_length;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+/**
+ * shrm_write_msg_to_fifo() - write message to FIFO
+ * @shrm:	pointer to shrm device information structure
+ * @channel:	audio or common channel
+ * @l2header:	L2 header or device ID
+ * @addr:	pointer to write buffer address
+ * @length:	length of mst to write
+ *
+ * Function Which Writes the data into Fifo in IPC zone
+ * It is called from shrm_write_msg. This function will copy the msg
+ * from the kernel buffer to FIFO. There are 4 kernel buffers from where
+ * the data is to copied to FIFO one for each of the messages ISI, RPC,
+ * AUDIO and SECURITY. ISI, RPC and SECURITY messages are pushed to FIFO
+ * in commmon channel and AUDIO message is pushed onto audio channel FIFO.
+ */
+int shrm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+				u8 l2header, void *addr, u32 length)
+{
+	struct fifo_write_params *fifo = NULL;
+	u32 l1_header = 0, l2_header = 0;
+	u32 requiredsize;
+	u32 size = 0;
+	u32 *msg;
+	u8 *src;
+
+	if (channel == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else if (channel == AUDIO_CHANNEL)
+		fifo = &ape_shrm_fifo_1;
+	else {
+		dev_err(shrm->dev, "invalid channel\n");
+		return -EINVAL;
+	}
+
+	/* L2 size in 32b */
+	requiredsize = ((length + 3) / 4);
+	/* Add size of L1 & L2 header */
+	requiredsize += 2;
+
+	/* if availablesize = or < requiredsize then error */
+	if (fifo->availablesize <= requiredsize) {
+		/* Fatal ERROR - should never happens */
+		dev_dbg(shrm->dev, "wr_wptr= %x\n",
+					fifo->writer_local_wptr);
+		dev_dbg(shrm->dev, "wr_rptr= %x\n",
+					fifo->writer_local_rptr);
+		dev_dbg(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_dbg(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_dbg(shrm->dev, "availsize= %x\n",
+						fifo->availablesize);
+		dev_dbg(shrm->dev, "end__fifo= %x\n",
+				fifo->end_addr_fifo);
+		dev_warn(shrm->dev, "Modem is busy, please wait."
+				" c_cnt = %d; a_cnt = %d\n", msg_common_counter,
+				msg_audio_counter);
+		if (channel == COMMON_CHANNEL) {
+			dev_warn(shrm->dev,
+					"Modem is lagging behind in reading."
+					"Stopping n/w dev queue\n");
+			shrm_stop_netdev(shrm->ndev);
+		}
+
+		return -EAGAIN;
+	}
+
+	if (channel == COMMON_CHANNEL) {
+		/* build L1 header */
+		l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+				(((msg_common_counter++) << COUNTER_OFFSET)
+				 & MASK_40_55_BIT) |
+				((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+	} else if (channel == AUDIO_CHANNEL) {
+		/* build L1 header */
+		l1_header = ((L1_NORMAL_MSG << L1_MSG_MAPID_OFFSET) |
+				(((msg_audio_counter++) << COUNTER_OFFSET)
+				 & MASK_40_55_BIT) |
+				((length + L2_HEADER_SIZE) & MASK_0_39_BIT));
+	}
+
+	/*
+	 * Need to take care race condition for fifo->availablesize
+	 * & fifo->writer_local_rptr with Ac_Read_notification interrupt.
+	 * One option could be use stack variable for LocalRptr and recompute
+	 * fifo->availablesize,based on flag enabled in the
+	 * Ac_read_notification
+	 */
+	l2_header = ((l2header << L2_HEADER_OFFSET) |
+					((length) & MASK_0_39_BIT));
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Check Local Rptr is less than or equal to Local WPtr */
+	if (fifo->writer_local_rptr <= fifo->writer_local_wptr) {
+		msg = (u32 *)
+			(fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+
+		/* check enough place bewteen writer_local_wptr & end of FIFO */
+		if ((fifo->end_addr_fifo-fifo->writer_local_wptr) >=
+							requiredsize) {
+			/* Add L1 header and L2 header */
+			*msg = l1_header;
+			msg++;
+			*msg = l2_header;
+			msg++;
+
+			/* copy the l2 message in 1 memcpy */
+			memcpy((void *)msg, addr, length);
+			/* UpdateWptr */
+			fifo->writer_local_wptr += requiredsize;
+			fifo->availablesize -= requiredsize;
+			fifo->writer_local_wptr %= fifo->end_addr_fifo;
+		} else {
+			/*
+			 * message is split between and of FIFO and beg of FIFO
+			 * copy first part from writer_local_wptr to end of FIFO
+			 */
+			size = fifo->end_addr_fifo-fifo->writer_local_wptr;
+
+			if (size == 1) {
+				/* Add L1 header */
+				*msg = l1_header;
+				msg++;
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg =	(u32 *)
+						fifo->fifo_virtual_addr;
+				*msg = l2_header;
+				msg++;
+
+				/* copy the l3 message in 1 memcpy */
+				memcpy((void *)msg, addr, length);
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			} else if (size == 2) {
+				/* Add L1 header and L2 header */
+				*msg = l1_header;
+				msg++;
+				*msg = l2_header;
+				msg++;
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg =	(u32 *)
+						fifo->fifo_virtual_addr;
+				/* copy the l3 message in 1 memcpy */
+				memcpy((void *)msg, addr, length);
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			} else {
+				/* Add L1 header and L2 header */
+				*msg = l1_header;
+				msg++;
+				*msg = l2_header;
+				msg++;
+
+				/* copy the l2 message in 1 memcpy */
+				memcpy((void *)msg, addr, (size-2)*4);
+
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr = 0;
+				fifo->availablesize -= size;
+
+				/*
+				 * copy second part from beg of FIFO
+				 * with remaining part of msg
+				 */
+				msg = (u32 *)fifo->fifo_virtual_addr;
+				src = (u8 *)addr+((size - 2) * 4);
+				memcpy((void *)msg, src,
+						(length-((size - 2) * 4)));
+
+				/* UpdateWptr */
+				fifo->writer_local_wptr +=
+							requiredsize-size;
+				fifo->availablesize -=
+							(requiredsize-size);
+			}
+
+		}
+	} else {
+		/* writer_local_rptr > writer_local_wptr */
+		msg = (u32 *)
+			(fifo->fifo_virtual_addr+fifo->writer_local_wptr);
+		/* Add L1 header and L2 header */
+		*msg = l1_header;
+		msg++;
+		*msg = l2_header;
+		msg++;
+		/*
+		 * copy message possbile between writer_local_wptr up
+		 * to writer_local_rptr copy the l3 message in 1 memcpy
+		 */
+		memcpy((void *)msg, addr, length);
+
+		/* UpdateWptr */
+		fifo->writer_local_wptr += requiredsize;
+		fifo->availablesize -= requiredsize;
+
+	}
+	spin_unlock_bh(&fifo->fifo_update_lock);
+	return length;
+}
+
+/**
+ * read_one_l2msg_common() - read message from common channel
+ * @shrm:	pointer to shrm device information structure
+ * @l2_msg:	pointer to the read L2 message buffer
+ * @len:	message length
+ *
+ * This function read one message from the FIFO  and returns l2 header type
+ */
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+			u8 *l2_msg, u32 *len)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+
+	u32 *msg;
+	u32 l1_header = 0;
+	u32 l2_header = 0;
+	u32 length;
+	u8 msgtype;
+	u32 msg_size;
+	u32 size = 0;
+
+	/* Read L1 header read content of reader_local_rptr */
+	msg = (u32 *)
+		(fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+	l1_header = *msg++;
+	msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+	if (msgtype != L1_NORMAL_MSG) {
+		/* Fatal ERROR - should never happens */
+		dev_info(shrm->dev, "wr_wptr= %x\n",
+						fifo->reader_local_wptr);
+		dev_info(shrm->dev, "wr_rptr= %x\n",
+						fifo->reader_local_rptr);
+		dev_info(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_info(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_info(shrm->dev, "availsize= %x\n",
+						fifo->availablesize);
+		dev_info(shrm->dev, "end_fifo= %x\n",
+						fifo->end_addr_fifo);
+		/* Fatal ERROR - should never happens */
+		dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+	 }
+	if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+		l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+		length = l2_header & MASK_0_39_BIT;
+	} else {
+		/* Read L2 header,Msg size & content of reader_local_rptr */
+		l2_header = *msg;
+		length = l2_header & MASK_0_39_BIT;
+	}
+
+	*len = length;
+	msg_size = ((length + 3) / 4);
+	msg_size += 2;
+
+	if (fifo->reader_local_rptr + msg_size <=
+						fifo->end_addr_fifo) {
+		/* Skip L2 header */
+		msg++;
+
+		/* read msg between reader_local_rptr and end of FIFO */
+		memcpy((void *)l2_msg, (void *)msg, length);
+		/* UpdateLocalRptr */
+		fifo->reader_local_rptr += msg_size;
+		fifo->reader_local_rptr %= fifo->end_addr_fifo;
+	} else {
+		/*
+		 * msg split between end of FIFO and beg copy first
+		 * part of msg read msg between reader_local_rptr
+		 * and end of FIFO
+		 */
+		size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+		if (size == 1) {
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else if (size == 2) {
+			/* Skip L2 header */
+			msg++;
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg,
+						(void *)(msg), length);
+		} else {
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+			/* copy second part of msg */
+			l2_msg += ((size - 2) * 4);
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg),
+						(length-((size - 2) * 4)));
+		}
+		fifo->reader_local_rptr =
+			(fifo->reader_local_rptr+msg_size) %
+				fifo->end_addr_fifo;
+	}
+	return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_common()
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+	/*
+	 * There won't be any Race condition reader_local_rptr &
+	 * fifo->reader_local_wptr with CaMsgpending Notification Interrupt
+	 */
+	return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ? 1 : 0);
+}
+
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+				u8 *l2_msg, u32 *len)
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	u32 *msg;
+	u32 l1_header = 0;
+	u32 l2_header = 0;
+	u32 length;
+	u8 msgtype;
+	u32 msg_size;
+	u32 size = 0;
+
+	/* Read L1 header read content of reader_local_rptr */
+	 msg = (u32 *)
+			(fifo->reader_local_rptr+fifo->fifo_virtual_addr);
+	 l1_header = *msg++;
+	 msgtype = (l1_header & 0xF0000000) >> L1_HEADER_MASK;
+
+	if (msgtype != L1_NORMAL_MSG) {
+		/* Fatal ERROR - should never happens */
+		dev_info(shrm->dev, "wr_local_wptr= %x\n",
+						fifo->reader_local_wptr);
+		dev_info(shrm->dev, "wr_local_rptr= %x\n",
+						fifo->reader_local_rptr);
+		dev_info(shrm->dev, "shared_wptr= %x\n",
+						fifo->shared_wptr);
+		dev_info(shrm->dev, "shared_rptr= %x\n",
+						fifo->shared_rptr);
+		dev_info(shrm->dev, "availsize=%x\n",
+						fifo->availablesize);
+		dev_info(shrm->dev, "end_fifo= %x\n",
+						fifo->end_addr_fifo);
+		dev_info(shrm->dev, "Received msgtype is %d\n", msgtype);
+		/* Fatal ERROR - should never happens */
+		dev_crit(shrm->dev, "Fatal ERROR - should never happen\n");
+		dev_info(shrm->dev, "Initiating a modem reset\n");
+		queue_kthread_work(&shrm->shrm_ac_wake_kw,
+				&shrm->shrm_mod_reset_req);
+	 }
+	if (fifo->reader_local_rptr == (fifo->end_addr_fifo-1)) {
+		l2_header = (*((u32 *)fifo->fifo_virtual_addr));
+		length = l2_header & MASK_0_39_BIT;
+	} else {
+		/* Read L2 header,Msg size & content of reader_local_rptr */
+		l2_header = *msg;
+		length = l2_header & MASK_0_39_BIT;
+	}
+
+	*len = length;
+	msg_size = ((length + 3) / 4);
+	msg_size += 2;
+
+	if (fifo->reader_local_rptr + msg_size <=
+						fifo->end_addr_fifo) {
+		/* Skip L2 header */
+		msg++;
+		/* read msg between reader_local_rptr and end of FIFO */
+		memcpy((void *)l2_msg, (void *)msg, length);
+		/* UpdateLocalRptr */
+		fifo->reader_local_rptr += msg_size;
+		fifo->reader_local_rptr %= fifo->end_addr_fifo;
+	} else {
+
+		/*
+		 * msg split between end of FIFO and beg
+		 * copy first part of msg
+		 * read msg between reader_local_rptr and end of FIFO
+		 */
+		size = fifo->end_addr_fifo-fifo->reader_local_rptr;
+		if (size == 1) {
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else if (size == 2) {
+			/* Skip L2 header */
+			msg++;
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg), length);
+		} else {
+			/* Skip L2 header */
+			msg++;
+			memcpy((void *)l2_msg, (void *)msg, ((size - 2) * 4));
+			/* copy second part of msg */
+			l2_msg += ((size - 2) * 4);
+			msg = (u32 *)(fifo->fifo_virtual_addr);
+			memcpy((void *)l2_msg, (void *)(msg),
+						(length-((size - 2) * 4)));
+		}
+		fifo->reader_local_rptr =
+			(fifo->reader_local_rptr+msg_size) %
+			fifo->end_addr_fifo;
+
+	}
+	return (l2_header>>L2_HEADER_OFFSET) & MASK_0_15_BIT;
+ }
+
+u8 read_remaining_messages_audio()
+{
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	return ((fifo->reader_local_rptr != fifo->reader_local_wptr) ?
+									1 : 0);
+}
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+						u8 channel, u32 length)
+{
+	struct fifo_write_params *fifo = NULL;
+	u32 messagesize = 0;
+	u8 is_only_one_unread_msg = 0;
+
+	if (channel == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else /* channel = AUDIO_CHANNEL */
+		fifo = &ape_shrm_fifo_1;
+
+	/* L3 size in 32b */
+	messagesize = ((length + 3) / 4);
+	/* Add size of L1 & L2 header */
+	messagesize += 2;
+	/*
+	 * possibility of race condition with Ac Read notification interrupt.
+	 * need to check ?
+	 */
+	if (fifo->writer_local_wptr > fifo->writer_local_rptr)
+		is_only_one_unread_msg =
+			((fifo->writer_local_rptr + messagesize) ==
+			fifo->writer_local_wptr) ? 1 : 0;
+	else
+		/* Msg split between end of fifo and starting of Fifo */
+		is_only_one_unread_msg =
+			(((fifo->writer_local_rptr + messagesize) %
+			fifo->end_addr_fifo) == fifo->writer_local_wptr) ?
+									1 : 0;
+
+	return is_only_one_unread_msg;
+}
+
+void update_ca_common_local_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA common reader local write pointer with the
+	 * shared write pointer
+	 */
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_0;
+
+	fifo->shared_wptr =
+		(*((u32 *)shrm->ca_common_shared_wptr));
+	fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ca_audio_local_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA audio reader local write pointer with the
+	 * shared write pointer
+	 */
+	struct fifo_read_params *fifo = &cmt_shrm_fifo_1;
+
+	fifo->shared_wptr =
+		(*((u32 *)shrm->ca_audio_shared_wptr));
+	fifo->reader_local_wptr = fifo->shared_wptr;
+}
+
+void update_ac_common_local_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC common writer local read pointer with the
+	 * shared read pointer
+	 */
+	struct fifo_write_params *fifo;
+	u32 free_space = 0;
+
+	fifo = &ape_shrm_fifo_0;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	fifo->shared_rptr =
+		(*((u32 *)shrm->ac_common_shared_rptr));
+
+	if (fifo->shared_rptr >= fifo->writer_local_rptr)
+		free_space =
+			(fifo->shared_rptr-fifo->writer_local_rptr);
+	else {
+		free_space =
+			(fifo->end_addr_fifo-fifo->writer_local_rptr);
+		free_space += fifo->shared_rptr;
+	}
+
+	/* Chance of race condition of below variables with write_msg */
+	fifo->availablesize += free_space;
+	fifo->writer_local_rptr = fifo->shared_rptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_audio_local_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC audio writer local read pointer with the
+	 * shared read pointer
+	 */
+	struct fifo_write_params *fifo;
+	u32 free_space = 0;
+
+	fifo = &ape_shrm_fifo_1;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	fifo->shared_rptr =
+		(*((u32 *)shrm->ac_audio_shared_rptr));
+
+	if (fifo->shared_rptr >= fifo->writer_local_rptr)
+		free_space =
+			(fifo->shared_rptr-fifo->writer_local_rptr);
+	else {
+		free_space =
+			(fifo->end_addr_fifo-fifo->writer_local_rptr);
+		free_space += fifo->shared_rptr;
+	}
+
+	/* Chance of race condition of below variables with write_msg */
+	fifo->availablesize += free_space;
+	fifo->writer_local_rptr = fifo->shared_rptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_common_shared_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC common shared write pointer with the
+	 * local write pointer
+	 */
+	struct fifo_write_params *fifo;
+
+	fifo = &ape_shrm_fifo_0;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ac_common_shared_wptr)) =
+						fifo->writer_local_wptr;
+
+	fifo->shared_wptr = fifo->writer_local_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ac_audio_shared_wptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update AC audio shared write pointer with the
+	 * local write pointer
+	 */
+	struct fifo_write_params *fifo;
+
+	fifo = &ape_shrm_fifo_1;
+	spin_lock_bh(&fifo->fifo_update_lock);
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ac_audio_shared_wptr)) =
+						fifo->writer_local_wptr;
+	fifo->shared_wptr = fifo->writer_local_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void update_ca_common_shared_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA common shared read pointer with the
+	 * local read pointer
+	 */
+	struct fifo_read_params *fifo;
+
+	fifo = &cmt_shrm_fifo_0;
+
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ca_common_shared_rptr)) =
+						fifo->reader_local_rptr;
+	fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void update_ca_audio_shared_rptr(struct shrm_dev *shrm)
+{
+	/*
+	 * update CA audio shared read pointer with the
+	 * local read pointer
+	 */
+	struct fifo_read_params *fifo;
+
+	fifo = &cmt_shrm_fifo_1;
+
+	/* Update shared pointer fifo offset of the IPC zone */
+	(*((u32 *)shrm->ca_audio_shared_rptr)) =
+						fifo->reader_local_rptr;
+	fifo->shared_rptr = fifo->reader_local_rptr;
+}
+
+void get_reader_pointers(u8 channel_type, u32 *reader_local_rptr,
+				u32 *reader_local_wptr, u32 *shared_rptr)
+{
+	struct fifo_read_params *fifo = NULL;
+
+	if (channel_type == COMMON_CHANNEL)
+		fifo = &cmt_shrm_fifo_0;
+	else /* channel_type = AUDIO_CHANNEL */
+		fifo = &cmt_shrm_fifo_1;
+
+	*reader_local_rptr = fifo->reader_local_rptr;
+	*reader_local_wptr = fifo->reader_local_wptr;
+	*shared_rptr = fifo->shared_rptr;
+}
+
+void get_writer_pointers(u8 channel_type, u32 *writer_local_rptr,
+			 u32 *writer_local_wptr, u32 *shared_wptr)
+{
+	struct fifo_write_params *fifo = NULL;
+
+	if (channel_type == COMMON_CHANNEL)
+		fifo = &ape_shrm_fifo_0;
+	else /* channel_type = AUDIO_CHANNEL */
+		fifo = &ape_shrm_fifo_1;
+
+	spin_lock_bh(&fifo->fifo_update_lock);
+	*writer_local_rptr = fifo->writer_local_rptr;
+	*writer_local_wptr = fifo->writer_local_wptr;
+	*shared_wptr = fifo->shared_wptr;
+	spin_unlock_bh(&fifo->fifo_update_lock);
+}
+
+void set_ca_msg_0_read_notif_send(u8 val)
+{
+	cmt_read_notif_0_send = val;
+}
+
+u8 get_ca_msg_0_read_notif_send(void)
+{
+	return cmt_read_notif_0_send;
+}
+
+void set_ca_msg_1_read_notif_send(u8 val)
+{
+	cmt_read_notif_1_send = val;
+}
+
+u8 get_ca_msg_1_read_notif_send(void)
+{
+	return cmt_read_notif_1_send;
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_ioctl.h b/drivers/modem_shm/u8500_shm/shrm_ioctl.h
new file mode 100644
index 0000000..039839e
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_ioctl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef __MODEM_IPC_INCLUDED
+#define __MODEM_IPC_INCLUDED
+
+#define DLP_IOCTL_MAGIC_NUMBER 'M'
+#define COMMON_BUFFER_SIZE (1024*1024)
+
+/**
+DLP Message Structure for Userland
+*/
+struct t_dlp_message{
+	unsigned int offset;
+	unsigned int size;
+};
+
+/**
+mmap constants.
+*/
+enum t_dlp_mmap_params {
+	MMAP_DLQUEUE,
+	MMAP_ULQUEUE
+};
+
+/**
+DLP IOCTLs for Userland
+*/
+#define DLP_IOC_ALLOCATE_BUFFER \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 0, struct t_dlp_message *)
+#define DLP_IOC_DEALLOCATE_BUFFER \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 1, struct t_dlp_message *)
+#define DLP_IOC_GET_MESSAGE \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 2, struct t_dlp_message *)
+#define DLP_IOC_PUT_MESSAGE \
+	_IOWR(DLP_IOCTL_MAGIC_NUMBER, 3, struct t_dlp_message *)
+
+#endif /*__MODEM_IPC_INCLUDED*/
diff --git a/drivers/modem_shm/u8500_shm/shrm_net.c b/drivers/modem_shm/u8500_shm/shrm_net.c
new file mode 100644
index 0000000..28dbcd3
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_net.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/phonet.h>
+#include <linux/if_phonet.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+#include <net/phonet/phonet.h>
+#include <net/phonet/pep.h>
+
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_config.h"
+#include "shrm_net.h"
+#include "shrm.h"
+
+
+/**
+ * shrm_net_receive() - receive data and copy to user space buffer
+ * @dev:	pointer to the network device structure
+ *
+ * Copy data from ISI queue to the user space buffer.
+ */
+int shrm_net_receive(struct net_device *dev)
+{
+	struct sk_buff *skb;
+	struct isadev_context *isadev;
+	struct message_queue *q;
+	u32 msgsize;
+	u32 size = 0;
+	struct shrm_net_iface_priv *net_iface_priv =
+		(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	isadev = &shrm->isa_context->isadev[ISI_MESSAGING];
+	q = &isadev->dl_queue;
+
+	spin_lock_bh(&q->update_lock);
+	if (list_empty(&q->msg_list)) {
+		spin_unlock_bh(&q->update_lock);
+		dev_dbg(shrm->dev, "Empty Shrm queue\n");
+		return 0;
+	}
+	spin_unlock_bh(&q->update_lock);
+
+	msgsize = get_size_of_new_msg(q);
+	if (msgsize <= 0)
+		return msgsize;
+
+	/*
+	 * The packet has been retrieved from the transmission
+	 * medium. Build an skb around it, so upper layers can handle it
+	 */
+	skb = dev_alloc_skb(msgsize);
+	if (!skb) {
+		if (printk_ratelimit())
+			dev_notice(shrm->dev,
+			"isa rx: low on mem - packet dropped\n");
+		dev->stats.rx_dropped++;
+		goto out;
+	}
+
+	if ((q->readptr+msgsize) >= q->size) {
+		size = (q->size-q->readptr);
+		/*Copy First Part of msg*/
+		skb_copy_to_linear_data(skb,
+				(u8 *)(q->fifo_base + q->readptr), size);
+		skb_put(skb, size);
+
+		/*Copy Second Part of msg at the top of fifo*/
+		skb_copy_to_linear_data_offset(skb, size,
+				(u8 *)(q->fifo_base), (msgsize - size));
+		skb_put(skb, msgsize-size);
+
+	} else {
+		skb_copy_to_linear_data(skb,
+				(u8 *)(q->fifo_base+q->readptr), msgsize);
+		skb_put(skb, msgsize);
+	}
+
+	spin_lock_bh(&q->update_lock);
+	remove_msg_from_queue(q);
+	spin_unlock_bh(&q->update_lock);
+
+	skb_reset_mac_header(skb);
+	__skb_pull(skb, dev->hard_header_len);
+	/*Write metadata, and then pass to the receive level*/
+	skb->dev = dev;/*kmalloc(sizeof(struct net_device), GFP_ATOMIC);*/
+	skb->protocol = htons(ETH_P_PHONET);
+	skb->priority = 0;
+	skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+	if (likely(netif_rx_ni(skb) == NET_RX_SUCCESS)) {
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += msgsize;
+	} else
+		dev->stats.rx_dropped++;
+
+	return msgsize;
+out:
+	return -ENOMEM;
+}
+
+static int netdev_isa_open(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	shrm->netdev_flag_up = 1;
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+	netif_wake_queue(dev);
+	return 0;
+}
+
+static int netdev_isa_close(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	shrm->netdev_flag_up = 0;
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+	return 0;
+}
+
+static int netdev_isa_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct if_phonet_req *req = (struct if_phonet_req *)ifr;
+
+	switch (cmd) {
+	case SIOCPNGAUTOCONF:
+		req->ifr_phonet_autoconf.device = PN_DEV_HOST;
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static struct net_device_stats *netdev_isa_stats(struct net_device *dev)
+{
+	return &dev->stats;
+}
+
+/**
+ * netdev_isa_write() - write through the net interface
+ * @skb:	pointer to the socket buffer
+ * @dev:	pointer to the network device structure
+ *
+ * Copies data(ISI message) from the user buffer to the kernel buffer and
+ * schedule transfer thread to transmit the message to the modem via FIFO.
+ */
+static netdev_tx_t netdev_isa_write(struct sk_buff *skb, struct net_device *dev)
+{
+	int err;
+	int retval = 0;
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	/*
+	 * FIXME:
+	 * U8500 modem requires that Pipe created/enabled Indication should
+	 * be sent from the port corresponding to GPRS socket.
+	 * Also, the U8500 modem does not implement Pipe controller
+	 * which takes care of port manipulations for GPRS traffic.
+	 *
+	 * Now, APE has GPRS socket and the socket for sending
+	 * Indication msgs bound to different ports.
+	 * Phonet stack does not allow an indication msg to be sent
+	 * from GPRS socket, since Phonet stack assumes the presence
+	 * of Pipe controller in modem.
+	 *
+	 * So, due to lack of Pipe controller implementation in the
+	 * U8500 modem, carry out the port manipulation related to
+	 * GPRS traffic here.
+	 * Ideally, it should be done either by Pipe controller in
+	 * modem OR some implementation of Pipe controller on APE side
+	 */
+	if (skb->data[RESOURCE_ID_INDEX] == PN_PIPE) {
+		if ((skb->data[MSG_ID_INDEX] == PNS_PIPE_CREATED_IND) ||
+			(skb->data[MSG_ID_INDEX] == PNS_PIPE_ENABLED_IND) ||
+			(skb->data[MSG_ID_INDEX] == PNS_PIPE_DISABLED_IND))
+			skb->data[SRC_OBJ_INDEX] = skb->data[PIPE_HDL_INDEX];
+	}
+
+	spin_lock_bh(&shrm->isa_context->common_tx);
+	err = shrm_write_msg(shrm, ISI_MESSAGING, skb->data,
+			skb->len);
+	if (!err) {
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
+		retval = NETDEV_TX_OK;
+		dev_kfree_skb(skb);
+	} else {
+		dev->stats.tx_dropped++;
+		retval = NETDEV_TX_BUSY;
+	}
+	spin_unlock_bh(&shrm->isa_context->common_tx);
+
+	return retval;
+}
+
+static const struct net_device_ops shrm_netdev_ops = {
+	.ndo_open = netdev_isa_open,
+	.ndo_stop = netdev_isa_close,
+	.ndo_do_ioctl = netdev_isa_ioctl,
+	.ndo_start_xmit = netdev_isa_write,
+	.ndo_get_stats = netdev_isa_stats,
+};
+
+static void shrm_net_init(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv;
+
+	dev->netdev_ops = &shrm_netdev_ops;
+	dev->header_ops = &phonet_header_ops;
+	dev->type = ARPHRD_PHONET;
+	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+	dev->mtu = PHONET_MAX_MTU;
+	dev->hard_header_len = SHRM_HLEN;
+	dev->addr_len = PHONET_ALEN;
+	dev->tx_queue_len = PN_TX_QUEUE_LEN;
+	dev->destructor = free_netdev;
+	dev->dev_addr[0] = PN_LINK_ADDR;
+	net_iface_priv = netdev_priv(dev);
+	memset(net_iface_priv, 0 , sizeof(struct shrm_net_iface_priv));
+}
+
+int shrm_register_netdev(struct shrm_dev *shrm)
+{
+	struct net_device *nw_device;
+	struct shrm_net_iface_priv *net_iface_priv;
+	char *devname = "shrm%d";
+	int err;
+
+	/* allocate the net device */
+	nw_device = shrm->ndev = alloc_netdev(
+			sizeof(struct shrm_net_iface_priv),
+			devname, shrm_net_init);
+	if (nw_device == NULL) {
+		dev_err(shrm->dev, "Failed to allocate SHRM Netdev\n");
+		return -ENOMEM;
+	}
+	err = register_netdev(shrm->ndev);
+	if (err) {
+		dev_err(shrm->dev, "Err %i in reg shrm-netdev\n", err);
+		free_netdev(shrm->ndev);
+		return -ENODEV;
+	}
+	dev_info(shrm->dev, "Registered shrm netdev\n");
+
+	net_iface_priv = (struct shrm_net_iface_priv *)netdev_priv(nw_device);
+	net_iface_priv->shrm_device = shrm;
+	net_iface_priv->iface_num = 0;
+
+	return err;
+}
+
+int shrm_stop_netdev(struct net_device *dev)
+{
+	netif_stop_queue(dev);
+	return 0;
+}
+
+int shrm_restart_netdev(struct net_device *dev)
+{
+	if (netif_queue_stopped(dev))
+		netif_wake_queue(dev);
+	return 0;
+}
+
+int shrm_start_netdev(struct net_device *dev)
+{
+	struct shrm_net_iface_priv *net_iface_priv =
+			(struct shrm_net_iface_priv *)netdev_priv(dev);
+	struct shrm_dev *shrm = net_iface_priv->shrm_device;
+
+	if (!netif_carrier_ok(dev))
+		netif_carrier_on(dev);
+	netif_start_queue(dev);
+	shrm->netdev_flag_up = 1;
+	return 0;
+}
+
+int shrm_suspend_netdev(struct net_device *dev)
+{
+	if (netif_running(dev))
+		netif_stop_queue(dev);
+	netif_device_detach(dev);
+	return 0;
+}
+
+int shrm_resume_netdev(struct net_device *dev)
+{
+	netif_device_attach(dev);
+	if (netif_running(dev))
+		netif_wake_queue(dev);
+	return 0;
+}
+
+void shrm_unregister_netdev(struct shrm_dev *shrm)
+{
+	unregister_netdev(shrm->ndev);
+}
diff --git a/drivers/modem_shm/u8500_shm/shrm_net.h b/drivers/modem_shm/u8500_shm/shrm_net.h
new file mode 100644
index 0000000..19eb768
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_net.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2009
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_NET_H
+#define __SHRM_NET_H
+
+#define SHRM_HLEN 1
+#define PHONET_ALEN 1
+
+#define PN_PIPE		0xD9
+#define PN_DEV_HOST	0x00
+#define PN_LINK_ADDR	0x26
+#define PN_TX_QUEUE_LEN	3
+
+#define RESOURCE_ID_INDEX	3
+#define SRC_OBJ_INDEX		7
+#define MSG_ID_INDEX		9
+#define PIPE_HDL_INDEX		10
+#define NETLINK_SHRM            20
+
+/**
+ * struct shrm_net_iface_priv - shrm net interface device information
+ * @shrm_device:	pointer to the shrm device information structure
+ * @iface_num:		flag used to indicate the up/down of netdev
+ */
+struct shrm_net_iface_priv {
+	struct shrm_dev *shrm_device;
+	unsigned int iface_num;
+};
+
+int shrm_register_netdev(struct shrm_dev *shrm_dev_data);
+int shrm_net_receive(struct net_device *dev);
+int shrm_suspend_netdev(struct net_device *dev);
+int shrm_resume_netdev(struct net_device *dev);
+int shrm_stop_netdev(struct net_device *dev);
+int shrm_restart_netdev(struct net_device *dev);
+int shrm_start_netdev(struct net_device *dev);
+void shrm_unregister_netdev(struct shrm_dev *shrm_dev_data);
+
+#endif /* __SHRM_NET_H */
diff --git a/drivers/modem_shm/u8500_shm/shrm_private.h b/drivers/modem_shm/u8500_shm/shrm_private.h
new file mode 100644
index 0000000..b605d68
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_private.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __SHRM_PRIVATE_INCLUDED
+#define __SHRM_PRIVATE_INCLUDED
+
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "shrm.h"
+
+#define GOP_OUTPUT_REGISTER_BASE (0x0)
+#define GOP_SET_REGISTER_BASE    (0x4)
+#define GOP_CLEAR_REGISTER_BASE  (0x8)
+#define GOP_TOGGLE_REGISTER_BASE (0xc)
+
+
+#define GOP_AUDIO_AC_READ_NOTIFICATION_BIT (0)
+#define GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT (1)
+#define GOP_COMMON_AC_READ_NOTIFICATION_BIT (2)
+#define GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT (3)
+#define GOP_CA_WAKE_REQ_BIT (7)
+#define GOP_AUDIO_CA_READ_NOTIFICATION_BIT (23)
+#define GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT (24)
+#define GOP_COMMON_CA_READ_NOTIFICATION_BIT (25)
+#define GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT (26)
+#define GOP_CA_WAKE_ACK_BIT (27)
+
+#define L2_MSG_MAPID_OFFSET (24)
+#define L1_MSG_MAPID_OFFSET (28)
+
+#define SHRM_SLEEP_STATE (0)
+#define SHRM_PTR_FREE (1)
+#define SHRM_PTR_BUSY (2)
+#define SHRM_IDLE (3)
+
+#define ISI_MESSAGING (0)
+#define RPC_MESSAGING (1)
+#define AUDIO_MESSAGING (2)
+#define SECURITY_MESSAGING (3)
+#define COMMON_LOOPBACK_MESSAGING (0xC0)
+#define AUDIO_LOOPBACK_MESSAGING (0x80)
+#define CIQ_MESSAGING (0xC3)
+#define RTC_CAL_MESSAGING (0xC8)
+
+#define COMMON_CHANNEL		0
+#define AUDIO_CHANNEL		1
+
+typedef void (*MSG_PENDING_NOTIF)(const u32 Wptr);
+
+/**
+ * struct fifo_write_params - parameters used for FIFO write operation.
+ * @writer_local_rptr:	pointer to local read buffer
+ * @writer_local_wptr:	pointer to local write buffer
+ * @shared_wptr:	write pointer shared by cmt and ape
+ * @shared_rptr:	read pointer shared by cmt and ape
+ * @availablesize:	available memory in fifo
+ * @end_addr_fifo:	fifo end addr
+ * @fifo_virtual_addr:	fifo virtual addr
+ * @fifo_update_lock:	spin lock to update fifo.
+ *
+ * On writting a message to FIFO the same has to be read by the modem before
+ * writing the next message to the FIFO. In oder to over come this a local
+ * write and read pointer is used for internal purpose.
+ */
+struct fifo_write_params {
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+	u32 shared_rptr;
+	u32 availablesize;
+	u32 end_addr_fifo;
+	u32 *fifo_virtual_addr;
+	spinlock_t fifo_update_lock;
+} ;
+
+/**
+ * struct fifo_read_params - parameters used for FIFO read operation
+ * @reader_local_rptr:	pointer to local read buffer
+ * @reader_local_wptr:	pointer to local write buffer
+ * @shared_wptr:	write pointer shared by cmt and ape
+ * @shared_rptr:	read pointer shared by cmt and ape
+ * @availablesize:	available memory in fifo
+ * @end_addr_fifo:	fifo end add
+ * @fifo_virtual_addr:	fifo virtual addr
+ */
+struct fifo_read_params{
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_wptr;
+	u32 shared_rptr;
+	u32 availablesize;
+	u32 end_addr_fifo;
+	u32 *fifo_virtual_addr;
+
+} ;
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+			received_msg_handler common_rx_handler,
+			received_msg_handler audio_rx_handler);
+void shrm_protocol_deinit(struct shrm_dev *shrm);
+void shrm_fifo_init(struct shrm_dev *shrm);
+int shrm_write_msg_to_fifo(struct shrm_dev *shrm, u8 channel,
+				u8 l2header, void *addr, u32 length);
+int shrm_write_msg(struct shrm_dev *shrm,
+			u8 l2_header, void *addr, u32 length);
+
+u8 is_the_only_one_unread_message(struct shrm_dev *shrm,
+						u8 channel, u32 length);
+u8 read_remaining_messages_common(void);
+u8 read_remaining_messages_audio(void);
+u8 read_one_l2msg_audio(struct shrm_dev *shrm,
+			u8 *p_l2_msg, u32 *p_len);
+u8 read_one_l2msg_common(struct shrm_dev *shrm,
+				u8 *p_l2_msg, u32 *p_len);
+void receive_messages_common(struct shrm_dev *shrm);
+void receive_messages_audio(struct shrm_dev *shrm);
+
+void update_ac_common_local_rptr(struct shrm_dev *shrm);
+void update_ac_audio_local_rptr(struct shrm_dev *shrm);
+void update_ca_common_local_wptr(struct shrm_dev *shrm);
+void update_ca_audio_local_wptr(struct shrm_dev *shrm);
+void update_ac_common_shared_wptr(struct shrm_dev *shrm);
+void update_ac_audio_shared_wptr(struct shrm_dev *shrm);
+void update_ca_common_shared_rptr(struct shrm_dev *shrm);
+void update_ca_audio_shared_rptr(struct shrm_dev *shrm);
+
+
+void get_writer_pointers(u8 msg_type, u32 *WriterLocalRptr, \
+			u32 *WriterLocalWptr, u32 *SharedWptr);
+void get_reader_pointers(u8 msg_type, u32 *ReaderLocalRptr, \
+			u32 *ReaderLocalWptr, u32 *SharedRptr);
+u8 read_boot_info_req(struct shrm_dev *shrm,
+				u32 *pConfig,
+				u32 *pVersion);
+void write_boot_info_resp(struct shrm_dev *shrm, u32 Config,
+							u32 Version);
+
+void send_ac_msg_pending_notification_0(struct shrm_dev *shrm);
+void send_ac_msg_pending_notification_1(struct shrm_dev *shrm);
+void ca_msg_read_notification_0(struct shrm_dev *shrm);
+void ca_msg_read_notification_1(struct shrm_dev *shrm);
+
+void set_ca_msg_0_read_notif_send(u8 val);
+u8 get_ca_msg_0_read_notif_send(void);
+void set_ca_msg_1_read_notif_send(u8 val);
+u8 get_ca_msg_1_read_notif_send(void);
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr);
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr);
+
+void shrm_ca_msgpending_0_tasklet(unsigned long);
+void shrm_ca_msgpending_1_tasklet(unsigned long);
+void shrm_ac_read_notif_0_tasklet(unsigned long);
+void shrm_ac_read_notif_1_tasklet(unsigned long);
+void shrm_ca_wake_req_tasklet(unsigned long);
+
+u8 get_boot_state(void);
+
+int get_ca_wake_req_state(void);
+
+/* shrm character interface */
+int isa_init(struct shrm_dev *shrm);
+void isa_exit(struct shrm_dev *shrm);
+int add_msg_to_queue(struct message_queue *q, u32 size);
+ssize_t isa_read(struct file *filp, char __user *buf, size_t len,
+							loff_t *ppos);
+int get_size_of_new_msg(struct message_queue *q);
+int remove_msg_from_queue(struct message_queue *q);
+void shrm_char_reset_queues(struct shrm_dev *shrm);
+int shrm_get_cdev_index(u8 l2_header);
+int shrm_get_cdev_l2header(u8 idx);
+
+#endif
diff --git a/drivers/modem_shm/u8500_shm/shrm_protocol.c b/drivers/modem_shm/u8500_shm/shrm_protocol.c
new file mode 100644
index 0000000..907926a
--- /dev/null
+++ b/drivers/modem_shm/u8500_shm/shrm_protocol.c
@@ -0,0 +1,1591 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun Murthy <arun.murthy@stericsson.com>
+ *	Kumar Sanghvi for ST-Ericsson
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/netlink.h>
+#include <linux/kthread.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mfd/abx500.h>
+#include <linux/modem_shm/modem_client.h>
+
+#include "shrm.h"
+#include "shrm_driver.h"
+#include "shrm_private.h"
+#include "shrm_net.h"
+
+#define L2_HEADER_ISI		0x0
+#define L2_HEADER_RPC		0x1
+#define L2_HEADER_AUDIO		0x2
+#define L2_HEADER_SECURITY	0x3
+#define L2_HEADER_COMMON_SIMPLE_LOOPBACK	0xC0
+#define L2_HEADER_COMMON_ADVANCED_LOOPBACK	0xC1
+#define L2_HEADER_AUDIO_SIMPLE_LOOPBACK		0x80
+#define L2_HEADER_AUDIO_ADVANCED_LOOPBACK	0x81
+#define L2_HEADER_CIQ		0xC3
+#define L2_HEADER_RTC_CALIBRATION		0xC8
+#define MAX_PAYLOAD 1024
+#define MOD_STUCK_TIMEOUT	6
+#define FIFO_FULL_TIMEOUT	1
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE	BIT(0)
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE	BIT(1)
+#define PRCM_MOD_AWAKE_STATUS_PRCM_MOD_VMODEM_OFF_ISO	BIT(2)
+#define PRCM_MOD_PURESET	BIT(0)
+#define PRCM_MOD_SW_RESET	BIT(1)
+
+#define PRCM_HOSTACCESS_REQ	0x334
+#define PRCM_MOD_AWAKE_STATUS	0x4A0
+#define PRCM_MOD_RESETN_VAL	0x204
+
+static u8 boot_state = BOOT_INIT;
+static u8 recieve_common_msg[8*1024];
+static u8 recieve_audio_msg[8*1024];
+static received_msg_handler rx_common_handler;
+static received_msg_handler rx_audio_handler;
+static struct hrtimer timer;
+static struct hrtimer mod_stuck_timer_0;
+static struct hrtimer mod_stuck_timer_1;
+static struct hrtimer fifo_full_timer;
+struct sock *shrm_nl_sk;
+
+static char shrm_common_tx_state = SHRM_SLEEP_STATE;
+static char shrm_common_rx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_tx_state = SHRM_SLEEP_STATE;
+static char shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+static atomic_t ac_sleep_disable_count = ATOMIC_INIT(0);
+static atomic_t ac_msg_pend_1 = ATOMIC_INIT(0);
+static atomic_t mod_stuck = ATOMIC_INIT(0);
+static atomic_t fifo_full = ATOMIC_INIT(0);
+static struct shrm_dev *shm_dev;
+
+/* Spin lock and tasklet declaration */
+DECLARE_TASKLET(shrm_ca_0_tasklet, shrm_ca_msgpending_0_tasklet, 0);
+DECLARE_TASKLET(shrm_ca_1_tasklet, shrm_ca_msgpending_1_tasklet, 0);
+DECLARE_TASKLET(shrm_ac_read_0_tasklet, shrm_ac_read_notif_0_tasklet, 0);
+DECLARE_TASKLET(shrm_ac_read_1_tasklet, shrm_ac_read_notif_1_tasklet, 0);
+
+static DEFINE_MUTEX(ac_state_mutex);
+
+static DEFINE_SPINLOCK(ca_common_lock);
+static DEFINE_SPINLOCK(ca_audio_lock);
+static DEFINE_SPINLOCK(ca_wake_req_lock);
+static DEFINE_SPINLOCK(boot_lock);
+static DEFINE_SPINLOCK(mod_stuck_lock);
+static DEFINE_SPINLOCK(start_timer_lock);
+
+enum shrm_nl {
+	SHRM_NL_MOD_RESET = 1,
+	SHRM_NL_MOD_QUERY_STATE,
+	SHRM_NL_USER_MOD_RESET,
+	SHRM_NL_STATUS_MOD_ONLINE,
+	SHRM_NL_STATUS_MOD_OFFLINE,
+};
+
+static int check_modem_in_reset(void);
+
+void shrm_print_dbg_info_work(struct kthread_work *work)
+{
+#if SHRM_DEBUG
+	abx500_dump_all_banks();
+	prcmu_debug_dump_regs();
+	prcmu_debug_dump_data_mem();
+#endif
+}
+
+void shrm_mod_reset_req_work(struct kthread_work *work)
+{
+	unsigned long flags;
+
+	/* update the boot_state */
+	spin_lock_irqsave(&boot_lock, flags);
+	if (boot_state != BOOT_DONE) {
+		dev_info(shm_dev->dev, "Modem in reset state\n");
+		spin_unlock_irqrestore(&boot_lock, flags);
+		return;
+	}
+	boot_state = BOOT_UNKNOWN;
+	wmb();
+	spin_unlock_irqrestore(&boot_lock, flags);
+	dev_err(shm_dev->dev, "APE makes modem reset\n");
+	prcmu_modem_reset();
+}
+
+static void shrm_ac_sleep_req_work(struct kthread_work *work)
+{
+	mutex_lock(&ac_state_mutex);
+	if (atomic_read(&ac_sleep_disable_count) == 0)
+		modem_release(shm_dev->modem);
+	mutex_unlock(&ac_state_mutex);
+}
+
+static void shrm_ac_wake_req_work(struct kthread_work *work)
+{
+	mutex_lock(&ac_state_mutex);
+	if (modem_request(shm_dev->modem) < 0) {
+		dev_err(shm_dev->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	}
+
+	mutex_unlock(&ac_state_mutex);
+}
+
+static u32 get_host_accessport_val(void)
+{
+	u32 prcm_hostaccess;
+	u32 status;
+	u32 reset_stats;
+
+	status = (prcmu_read(PRCM_MOD_AWAKE_STATUS) & 0x03);
+	reset_stats = (prcmu_read(PRCM_MOD_RESETN_VAL) & 0x03);
+	prcm_hostaccess = prcmu_read(PRCM_HOSTACCESS_REQ);
+	wmb();
+	prcm_hostaccess = ((prcm_hostaccess & 0x01) &&
+		(status == (PRCM_MOD_AWAKE_STATUS_PRCM_MOD_AAPD_AWAKE |
+			    PRCM_MOD_AWAKE_STATUS_PRCM_MOD_COREPD_AWAKE)) &&
+		(reset_stats == (PRCM_MOD_SW_RESET | PRCM_MOD_PURESET)));
+
+	return prcm_hostaccess;
+}
+
+static enum hrtimer_restart shrm_fifo_full_timeout(struct hrtimer *timer)
+{
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart shrm_mod_stuck_timeout(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mod_stuck_lock, flags);
+	/* Check MSR is already in progress */
+	if (shm_dev->msr_flag || boot_state == BOOT_UNKNOWN ||
+			atomic_read(&mod_stuck) || atomic_read(&fifo_full)) {
+		spin_unlock_irqrestore(&mod_stuck_lock, flags);
+		return HRTIMER_NORESTART;
+	}
+	atomic_set(&mod_stuck, 1);
+	spin_unlock_irqrestore(&mod_stuck_lock, flags);
+	dev_err(shm_dev->dev, "No response from modem, timeout %dsec\n",
+			MOD_STUCK_TIMEOUT);
+	dev_err(shm_dev->dev, "APE initiating MSR\n");
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+	return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart callback(struct hrtimer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ca_wake_req_lock, flags);
+	if (((shrm_common_rx_state == SHRM_IDLE) ||
+				(shrm_common_rx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_common_tx_state == SHRM_IDLE) ||
+				(shrm_common_tx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_audio_rx_state == SHRM_IDLE)  ||
+				(shrm_audio_rx_state == SHRM_SLEEP_STATE))
+			&& ((shrm_audio_tx_state == SHRM_IDLE)  ||
+				(shrm_audio_tx_state == SHRM_SLEEP_STATE))) {
+
+		shrm_common_rx_state = SHRM_SLEEP_STATE;
+		shrm_audio_rx_state = SHRM_SLEEP_STATE;
+		shrm_common_tx_state = SHRM_SLEEP_STATE;
+		shrm_audio_tx_state = SHRM_SLEEP_STATE;
+
+		queue_kthread_work(&shm_dev->shrm_ac_sleep_kw,
+				&shm_dev->shrm_ac_sleep_req);
+
+	}
+	spin_unlock_irqrestore(&ca_wake_req_lock, flags);
+
+	return HRTIMER_NORESTART;
+}
+
+int nl_send_multicast_message(int msg, gfp_t gfp_mask)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh = NULL;
+	int err;
+
+	/* prepare netlink message */
+	skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), gfp_mask);
+	if (!skb) {
+		dev_err(shm_dev->dev, "%s:alloc_skb failed\n", __func__);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+	dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+	nlh->nlmsg_pid = 0;  /* from kernel */
+	nlh->nlmsg_flags = 0;
+	*(int *)NLMSG_DATA(nlh) = msg;
+	skb_put(skb, MAX_PAYLOAD);
+	/* sender is in group 1<<0 */
+	NETLINK_CB(skb).pid = 0;  /* from kernel */
+	/* to mcast group 1<<0 */
+	NETLINK_CB(skb).dst_group = 1;
+
+	/*multicast the message to all listening processes*/
+	err = netlink_broadcast(shrm_nl_sk, skb, 0, 1, gfp_mask);
+	dev_dbg(shm_dev->dev, "ret val from nl-multicast = %d\n", err);
+
+out:
+	return err;
+}
+
+static void nl_send_unicast_message(int dst_pid)
+{
+	struct sk_buff *skb = NULL;
+	struct nlmsghdr *nlh = NULL;
+	int err;
+	int bt_state;
+	unsigned long flags;
+
+	dev_dbg(shm_dev->dev, "Sending unicast message\n");
+
+	/* prepare the NL message for unicast */
+	skb = alloc_skb(NLMSG_SPACE(MAX_PAYLOAD), GFP_KERNEL);
+	if (!skb) {
+		dev_err(shm_dev->dev, "%s:alloc_skb failed\n", __func__);
+		return;
+	}
+
+	nlh = (struct nlmsghdr *)skb->data;
+	nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
+	dev_dbg(shm_dev->dev, "nlh->nlmsg_len = %d\n", nlh->nlmsg_len);
+
+	nlh->nlmsg_pid = 0;  /* from kernel */
+	nlh->nlmsg_flags = 0;
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	if (bt_state == BOOT_DONE)
+		*(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_ONLINE;
+	else
+		*(int *)NLMSG_DATA(nlh) = SHRM_NL_STATUS_MOD_OFFLINE;
+
+	skb_put(skb, MAX_PAYLOAD);
+	/* sender is in group 1<<0 */
+	NETLINK_CB(skb).pid = 0;  /* from kernel */
+	NETLINK_CB(skb).dst_group = 0;
+
+	/*unicast the message to the querying processes*/
+	err = netlink_unicast(shrm_nl_sk, skb, dst_pid, MSG_DONTWAIT);
+	dev_dbg(shm_dev->dev, "ret val from nl-unicast = %d\n", err);
+}
+
+
+static int check_modem_in_reset(void)
+{
+	u8 bt_state;
+	unsigned long flags;
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	if (bt_state != BOOT_UNKNOWN &&
+			(!readl(shm_dev->ca_reset_status_rptr)))
+		return 0;
+	else
+		return -ENODEV;
+#else
+	/*
+	 * this check won't be applicable and won't work correctly
+	 * if modem-silent-feature is not enabled
+	 * so, simply return 0
+	 */
+	return 0;
+#endif
+}
+
+void shrm_ca_msgpending_0_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_rptr;
+	u32 config = 0, version = 0;
+	unsigned long flags;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	/* Interprocess locking */
+	spin_lock(&ca_common_lock);
+
+	/* Update_reader_local_wptr with shared_wptr */
+	update_ca_common_local_wptr(shrm);
+	get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+				&reader_local_wptr, &shared_rptr);
+
+	set_ca_msg_0_read_notif_send(0);
+
+	if (boot_state == BOOT_DONE) {
+		shrm_common_rx_state = SHRM_PTR_FREE;
+
+		if (reader_local_rptr != shared_rptr)
+			ca_msg_read_notification_0(shrm);
+		if (reader_local_rptr != reader_local_wptr)
+			receive_messages_common(shrm);
+		get_reader_pointers(COMMON_CHANNEL, &reader_local_rptr,
+				&reader_local_wptr, &shared_rptr);
+		if (reader_local_rptr == reader_local_wptr)
+			shrm_common_rx_state = SHRM_IDLE;
+	} else {
+		/* BOOT phase.only a BOOT_RESP should be in FIFO */
+		if (boot_state != BOOT_INFO_SYNC) {
+			if (!read_boot_info_req(shrm, &config, &version)) {
+				dev_err(shrm->dev,
+						"Unable to read boot state\n");
+				return;
+			}
+			/* SendReadNotification */
+			ca_msg_read_notification_0(shrm);
+			/*
+			 * Check the version number before
+			 * sending Boot info response
+			 */
+
+			/* send MsgPending notification */
+			write_boot_info_resp(shrm, config, version);
+			spin_lock_irqsave(&boot_lock, flags);
+			boot_state = BOOT_INFO_SYNC;
+			spin_unlock_irqrestore(&boot_lock, flags);
+			dev_info(shrm->dev, "BOOT_INFO_SYNC\n");
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		} else {
+			ca_msg_read_notification_0(shrm);
+			dev_info(shrm->dev,
+				"BOOT_INFO_SYNC\n");
+		}
+	}
+	/* Interprocess locking */
+	spin_unlock(&ca_common_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ca_msgpending_1_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 reader_local_rptr;
+	u32 reader_local_wptr;
+	u32 shared_rptr;
+
+	/*
+	 * This function is called when CaMsgPendingNotification Trigerred
+	 * by CMU. It means that CMU has wrote a message into Ca Audio FIFO
+	 */
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	/* Interprocess locking */
+	spin_lock(&ca_audio_lock);
+
+	/* Update_reader_local_wptr(with shared_wptr) */
+	update_ca_audio_local_wptr(shrm);
+	get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+					&reader_local_wptr, &shared_rptr);
+
+	set_ca_msg_1_read_notif_send(0);
+
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev, "Boot Error\n");
+		return;
+	}
+	shrm_audio_rx_state = SHRM_PTR_FREE;
+	/* Check we already read the message */
+	if (reader_local_rptr != shared_rptr)
+		ca_msg_read_notification_1(shrm);
+	if (reader_local_rptr != reader_local_wptr)
+		receive_messages_audio(shrm);
+
+	get_reader_pointers(AUDIO_CHANNEL, &reader_local_rptr,
+			&reader_local_wptr, &shared_rptr);
+	if (reader_local_rptr == reader_local_wptr)
+		shrm_audio_rx_state = SHRM_IDLE;
+
+	 /* Interprocess locking */
+	spin_unlock(&ca_audio_lock);
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ac_read_notif_0_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+	unsigned long flags;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	/* Update writer_local_rptrwith shared_rptr */
+	update_ac_common_local_rptr(shrm);
+	get_writer_pointers(COMMON_CHANNEL, &writer_local_rptr,
+				&writer_local_wptr, &shared_wptr);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	if (boot_state == BOOT_INFO_SYNC) {
+		/* BOOT_RESP sent by APE has been received by CMT */
+		spin_lock_irqsave(&boot_lock, flags);
+		boot_state = BOOT_DONE;
+		spin_unlock_irqrestore(&boot_lock, flags);
+		dev_info(shrm->dev, "IPC_ISA BOOT_DONE\n");
+
+		if (shrm->msr_flag) {
+			shrm_start_netdev(shrm->ndev);
+			shrm->msr_flag = 0;
+
+			/* multicast that modem is online */
+			nl_send_multicast_message(SHRM_NL_STATUS_MOD_ONLINE,
+					GFP_ATOMIC);
+		}
+
+	} else if (boot_state == BOOT_DONE) {
+		if (writer_local_rptr != writer_local_wptr) {
+			shrm_common_tx_state = SHRM_PTR_FREE;
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		} else {
+			shrm_common_tx_state = SHRM_IDLE;
+			shrm_restart_netdev(shrm->ndev);
+		}
+	} else {
+		dev_err(shrm->dev, "Invalid boot state\n");
+	}
+	/* start timer here */
+	hrtimer_start(&timer, ktime_set(0, 25*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ac_read_notif_1_tasklet(unsigned long tasklet_data)
+{
+	struct shrm_dev *shrm = (struct shrm_dev *)tasklet_data;
+	u32 writer_local_rptr;
+	u32 writer_local_wptr;
+	u32 shared_wptr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		return;
+	}
+
+	/* Update writer_local_rptr(with shared_rptr) */
+	update_ac_audio_local_rptr(shrm);
+	get_writer_pointers(AUDIO_CHANNEL, &writer_local_rptr,
+				&writer_local_wptr, &shared_wptr);
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev, "Error Case in boot state\n");
+		return;
+	}
+	if (writer_local_rptr != writer_local_wptr) {
+		shrm_audio_tx_state = SHRM_PTR_FREE;
+		queue_kthread_work(&shrm->shrm_audio_ch_wr_kw,
+				&shrm->send_ac_msg_pend_notify_1);
+	} else {
+		shrm_audio_tx_state = SHRM_IDLE;
+	}
+	/* start timer here */
+	hrtimer_start(&timer, ktime_set(0, 25*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+	atomic_dec(&ac_msg_pend_1);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_ca_sleep_req_work(struct kthread_work *work)
+{
+	u8 bt_state;
+	unsigned long flags;
+
+	dev_dbg(shm_dev->dev, "%s:IRQ_PRCMU_CA_SLEEP\n", __func__);
+
+	spin_lock_irqsave(&boot_lock, flags);
+	bt_state = boot_state;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if ((bt_state != BOOT_DONE) &&
+			(!readl(shm_dev->ca_reset_status_rptr))) {
+		dev_err(shm_dev->dev, "%s:Modem state reset or unknown\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+	shrm_common_rx_state = SHRM_IDLE;
+	shrm_audio_rx_state =  SHRM_IDLE;
+
+	if (!get_host_accessport_val()) {
+		dev_err(shm_dev->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+	writel((1<<GOP_CA_WAKE_ACK_BIT),
+		shm_dev->intr_base + GOP_SET_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	hrtimer_start(&timer, ktime_set(0, 10*NSEC_PER_MSEC),
+			HRTIMER_MODE_REL);
+	atomic_dec(&ac_sleep_disable_count);
+}
+
+void shrm_ca_wake_req_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work,
+			struct shrm_dev, shrm_ca_wake_req);
+
+	/* initialize the FIFO Variables */
+	if (boot_state == BOOT_INIT) {
+		shrm_fifo_init(shrm);
+	}
+	mutex_lock(&ac_state_mutex);
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	local_irq_save(flags);
+	preempt_disable();
+	/* send ca_wake_ack_interrupt to CMU */
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown\n",
+			__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+	}
+
+	/* send ca_wake_ack_interrupt to CMU */
+	writel((1<<GOP_CA_WAKE_ACK_BIT),
+			shm_dev->intr_base + GOP_SET_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+}
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+static int shrm_modem_reset_sequence(void)
+{
+	int err;
+	unsigned long flags;
+
+	hrtimer_cancel(&timer);
+	hrtimer_cancel(&mod_stuck_timer_0);
+	hrtimer_cancel(&mod_stuck_timer_1);
+	hrtimer_cancel(&fifo_full_timer);
+	atomic_set(&mod_stuck, 0);
+	atomic_set(&fifo_full, 0);
+	tasklet_disable_nosync(&shrm_ac_read_0_tasklet);
+	tasklet_disable_nosync(&shrm_ac_read_1_tasklet);
+	tasklet_disable_nosync(&shrm_ca_0_tasklet);
+	tasklet_disable_nosync(&shrm_ca_1_tasklet);
+
+	/*
+	 * keep the count to 0 so that we can bring down the line
+	 * for normal ac-wake and ac-sleep logic
+	 */
+	atomic_set(&ac_sleep_disable_count, 0);
+	atomic_set(&ac_msg_pend_1, 0);
+
+	/* workaround for MSR */
+	queue_kthread_work(&shm_dev->shrm_ac_wake_kw,
+			&shm_dev->shrm_ac_wake_req);
+
+	/* reset char device queues */
+	shrm_char_reset_queues(shm_dev);
+
+	/* reset protocol states */
+	shrm_common_tx_state = SHRM_SLEEP_STATE;
+	shrm_common_rx_state = SHRM_SLEEP_STATE;
+	shrm_audio_tx_state = SHRM_SLEEP_STATE;
+	shrm_audio_rx_state = SHRM_SLEEP_STATE;
+
+	/* set the msr flag */
+	shm_dev->msr_flag = 1;
+
+	/* multicast that modem is going to reset */
+	err = nl_send_multicast_message(SHRM_NL_MOD_RESET, GFP_ATOMIC);
+
+	/* reset the boot state */
+	spin_lock_irqsave(&boot_lock, flags);
+	boot_state = BOOT_INIT;
+	spin_unlock_irqrestore(&boot_lock, flags);
+
+	tasklet_enable(&shrm_ac_read_0_tasklet);
+	tasklet_enable(&shrm_ac_read_1_tasklet);
+	tasklet_enable(&shrm_ca_0_tasklet);
+	tasklet_enable(&shrm_ca_1_tasklet);
+	/* re-enable irqs */
+	enable_irq(shm_dev->ac_read_notif_0_irq);
+	enable_irq(shm_dev->ac_read_notif_1_irq);
+	enable_irq(shm_dev->ca_msg_pending_notif_0_irq);
+	enable_irq(shm_dev->ca_msg_pending_notif_1_irq);
+	enable_irq(IRQ_PRCMU_CA_WAKE);
+	enable_irq(IRQ_PRCMU_CA_SLEEP);
+
+	return err;
+}
+#endif
+
+static void shrm_modem_reset_callback(unsigned long irq)
+{
+	dev_err(shm_dev->dev, "Received mod_reset_req interrupt\n");
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	{
+		int err;
+		dev_warn(shm_dev->dev, "Initiating Modem silent reset\n");
+
+		err = shrm_modem_reset_sequence();
+		if (err)
+			dev_err(shm_dev->dev,
+				"Failed multicast of modem reset\n");
+	}
+#else
+	dev_info(shm_dev->dev, "Modem in reset loop, doing System reset\n");
+
+	/* Call the PRCMU reset API */
+	prcmu_system_reset(SW_RESET_NO_ARGUMENT);
+#endif
+}
+
+DECLARE_TASKLET(shrm_sw_reset_callback, shrm_modem_reset_callback,
+		IRQ_PRCMU_MODEM_SW_RESET_REQ);
+
+static irqreturn_t shrm_prcmu_irq_handler(int irq, void *data)
+{
+	struct shrm_dev *shrm = data;
+	unsigned long flags;
+
+	switch (irq) {
+	case IRQ_PRCMU_CA_WAKE:
+		if (shrm->msr_flag)
+			atomic_set(&ac_sleep_disable_count, 0);
+		atomic_inc(&ac_sleep_disable_count);
+		queue_kthread_work(&shrm->shrm_ca_wake_kw, &shrm->shrm_ca_wake_req);
+		break;
+	case IRQ_PRCMU_CA_SLEEP:
+		queue_kthread_work(&shrm->shrm_ca_wake_kw, &shrm->shrm_ca_sleep_req);
+		break;
+	case IRQ_PRCMU_MODEM_SW_RESET_REQ:
+		/* update the boot_state */
+		spin_lock_irqsave(&boot_lock, flags);
+		boot_state = BOOT_UNKNOWN;
+
+		/*
+		 * put a barrier over here to make sure boot_state is updated
+		 * else, it is seen that some of already executing modem
+		 * irqs or tasklets fail the protocol checks and will ultimately
+		 * try to acces the modem causing system to hang.
+		 * This is particularly seen with user-space initiated modem reset
+		 */
+		wmb();
+		spin_unlock_irqrestore(&boot_lock, flags);
+
+		disable_irq_nosync(shrm->ac_read_notif_0_irq);
+		disable_irq_nosync(shrm->ac_read_notif_1_irq);
+		disable_irq_nosync(shrm->ca_msg_pending_notif_0_irq);
+		disable_irq_nosync(shrm->ca_msg_pending_notif_1_irq);
+		disable_irq_nosync(IRQ_PRCMU_CA_WAKE);
+		disable_irq_nosync(IRQ_PRCMU_CA_SLEEP);
+
+		/* stop network queue */
+		shrm_stop_netdev(shm_dev->ndev);
+
+		tasklet_schedule(&shrm_sw_reset_callback);
+		break;
+	default:
+		dev_err(shrm->dev, "%s: => IRQ %d\n", __func__, irq);
+		return IRQ_NONE;
+	}
+	return IRQ_HANDLED;
+}
+
+static void send_ac_msg_pend_notify_0_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work, struct shrm_dev,
+			send_ac_msg_pend_notify_0);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	update_ac_common_shared_wptr(shrm);
+
+	mutex_lock(&ac_state_mutex);
+	atomic_inc(&ac_sleep_disable_count);
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shrm->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	spin_lock_irqsave(&start_timer_lock, flags);
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	/* Trigger AcMsgPendingNotification to CMU */
+	writel((1<<GOP_COMMON_AC_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+	/* timer to detect modem stuck or hang */
+	hrtimer_start(&mod_stuck_timer_0, ktime_set(MOD_STUCK_TIMEOUT, 0),
+			HRTIMER_MODE_REL);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (shrm_common_tx_state == SHRM_PTR_FREE)
+		shrm_common_tx_state = SHRM_PTR_BUSY;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+static void send_ac_msg_pend_notify_1_work(struct kthread_work *work)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = container_of(work, struct shrm_dev,
+			send_ac_msg_pend_notify_1);
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* Update shared_wptr with writer_local_wptr) */
+	update_ac_audio_shared_wptr(shrm);
+
+	mutex_lock(&ac_state_mutex);
+	if (!atomic_read(&ac_msg_pend_1)) {
+		atomic_inc(&ac_sleep_disable_count);
+		atomic_inc(&ac_msg_pend_1);
+	}
+	if (modem_request(shrm->modem) < 0) {
+		dev_err(shrm->dev,
+				"prcmu_ac_wake_req failed, initiating MSR\n");
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shm_dev->shrm_print_dbg_info);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+	}
+	mutex_unlock(&ac_state_mutex);
+
+	spin_lock_irqsave(&start_timer_lock, flags);
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		spin_unlock_irqrestore(&start_timer_lock, flags);
+		return;
+	}
+
+	/* Trigger AcMsgPendingNotification to CMU */
+	writel((1<<GOP_AUDIO_AC_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+	/* timer to detect modem stuck or hang */
+	hrtimer_start(&mod_stuck_timer_1, ktime_set(MOD_STUCK_TIMEOUT, 0),
+			HRTIMER_MODE_REL);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (shrm_audio_tx_state == SHRM_PTR_FREE)
+		shrm_audio_tx_state = SHRM_PTR_BUSY;
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void shrm_nl_receive(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = NULL;
+	int msg;
+
+	dev_dbg(shm_dev->dev, "Received NL msg from user-space\n");
+
+	nlh = (struct nlmsghdr *)skb->data;
+	msg = *((int *)(NLMSG_DATA(nlh)));
+	switch (msg) {
+	case SHRM_NL_MOD_QUERY_STATE:
+		dev_dbg(shm_dev->dev, "mod-query-state from user-space\n");
+		nl_send_unicast_message(nlh->nlmsg_pid);
+		break;
+
+	case SHRM_NL_USER_MOD_RESET:
+		dev_info(shm_dev->dev, "user-space inited mod-reset-req\n");
+		dev_info(shm_dev->dev, "PCRMU resets modem\n");
+		if (atomic_read(&mod_stuck) || atomic_read(&fifo_full)) {
+			dev_info(shm_dev->dev,
+					"Modem reset already in progress\n");
+			break;
+		}
+		atomic_set(&mod_stuck, 1);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+		break;
+
+	default:
+		dev_err(shm_dev->dev, "Invalid NL msg from user-space\n");
+		break;
+	};
+}
+
+int shrm_protocol_init(struct shrm_dev *shrm,
+			received_msg_handler common_rx_handler,
+			received_msg_handler audio_rx_handler)
+{
+	int err;
+	struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	struct netlink_kernel_cfg nl_cfg;
+#endif
+
+	shm_dev = shrm;
+	boot_state = BOOT_INIT;
+	dev_info(shrm->dev, "IPC_ISA BOOT_INIT\n");
+	rx_common_handler = common_rx_handler;
+	rx_audio_handler = audio_rx_handler;
+	atomic_set(&ac_sleep_disable_count, 0);
+
+	hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	timer.function = callback;
+	hrtimer_init(&mod_stuck_timer_0, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	mod_stuck_timer_0.function = shrm_mod_stuck_timeout;
+	hrtimer_init(&mod_stuck_timer_1, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	mod_stuck_timer_1.function = shrm_mod_stuck_timeout;
+	hrtimer_init(&fifo_full_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	fifo_full_timer.function = shrm_fifo_full_timeout;
+
+	init_kthread_worker(&shrm->shrm_common_ch_wr_kw);
+	shrm->shrm_common_ch_wr_kw_task = kthread_run(kthread_worker_fn,
+						     &shrm->shrm_common_ch_wr_kw,
+						     "shrm_common_channel_irq");
+	if (IS_ERR(shrm->shrm_common_ch_wr_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		return -ENOMEM;
+	}
+
+	init_kthread_worker(&shrm->shrm_audio_ch_wr_kw);
+	shrm->shrm_audio_ch_wr_kw_task = kthread_run(kthread_worker_fn,
+						    &shrm->shrm_audio_ch_wr_kw,
+						    "shrm_audio_channel_irq");
+	if (IS_ERR(shrm->shrm_audio_ch_wr_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw1;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_audio_ch_wr_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ac_wake_kw);
+	shrm->shrm_ac_wake_kw_task = kthread_run(kthread_worker_fn,
+						&shrm->shrm_ac_wake_kw,
+						"shrm_ac_wake_req");
+	if (IS_ERR(shrm->shrm_ac_wake_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw2;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_ac_wake_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ca_wake_kw);
+	shrm->shrm_ca_wake_kw_task = kthread_run(kthread_worker_fn,
+						&shrm->shrm_ca_wake_kw,
+						"shrm_ca_wake_req");
+	if (IS_ERR(shrm->shrm_ca_wake_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw3;
+	}
+	/* must use the FIFO scheduler as it is realtime sensitive */
+	sched_setscheduler(shrm->shrm_ca_wake_kw_task, SCHED_FIFO, &param);
+
+	init_kthread_worker(&shrm->shrm_ac_sleep_kw);
+	shrm->shrm_ac_sleep_kw_task = kthread_run(kthread_worker_fn,
+						 &shrm->shrm_ac_sleep_kw,
+						 "shrm_ac_sleep_req");
+	if (IS_ERR(shrm->shrm_ac_sleep_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw4;
+	}
+	init_kthread_worker(&shrm->shrm_mod_stuck_kw);
+	shrm->shrm_mod_stuck_kw_task = kthread_run(kthread_worker_fn,
+						     &shrm->shrm_mod_stuck_kw,
+						     "shrm_mod_reset_req");
+	if (IS_ERR(shrm->shrm_mod_stuck_kw_task)) {
+		dev_err(shrm->dev, "failed to create work task\n");
+		err = -ENOMEM;
+		goto free_kw5;
+	}
+
+	init_kthread_work(&shrm->send_ac_msg_pend_notify_0,
+			  send_ac_msg_pend_notify_0_work);
+	init_kthread_work(&shrm->send_ac_msg_pend_notify_1,
+			  send_ac_msg_pend_notify_1_work);
+	init_kthread_work(&shrm->shrm_ca_wake_req, shrm_ca_wake_req_work);
+	init_kthread_work(&shrm->shrm_ca_sleep_req, shrm_ca_sleep_req_work);
+	init_kthread_work(&shrm->shrm_ac_sleep_req, shrm_ac_sleep_req_work);
+	init_kthread_work(&shrm->shrm_ac_wake_req, shrm_ac_wake_req_work);
+	init_kthread_work(&shrm->shrm_mod_reset_req, shrm_mod_reset_req_work);
+	init_kthread_work(&shrm->shrm_print_dbg_info, shrm_print_dbg_info_work);
+
+	/* set tasklet data */
+	shrm_ca_0_tasklet.data = (unsigned long)shrm;
+	shrm_ca_1_tasklet.data = (unsigned long)shrm;
+
+	err = request_irq(IRQ_PRCMU_CA_SLEEP, shrm_prcmu_irq_handler,
+			IRQF_NO_SUSPEND, "ca-sleep", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_SLEEP.\n");
+		goto free_kw6;
+	}
+
+	err = request_irq(IRQ_PRCMU_CA_WAKE, shrm_prcmu_irq_handler,
+		IRQF_NO_SUSPEND, "ca-wake", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev, "Failed alloc IRQ_PRCMU_CA_WAKE.\n");
+		goto drop2;
+	}
+
+	err = request_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, shrm_prcmu_irq_handler,
+			IRQF_NO_SUSPEND, "modem-sw-reset-req", shrm);
+	if (err < 0) {
+		dev_err(shm_dev->dev,
+				"Failed alloc IRQ_PRCMU_MODEM_SW_RESET_REQ.\n");
+		goto drop1;
+	}
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+	nl_cfg.input = shrm_nl_receive;
+	nl_cfg.cb_mutex = NULL;
+	/* init netlink socket for user-space communication */
+	shrm_nl_sk = netlink_kernel_create(NULL, NETLINK_SHRM, THIS_MODULE, &nl_cfg);
+
+	if (!shrm_nl_sk) {
+		dev_err(shm_dev->dev, "netlink socket creation failed\n");
+		goto drop;
+	}
+#endif
+	return 0;
+
+#ifdef CONFIG_U8500_SHRM_MODEM_SILENT_RESET
+drop:
+	free_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, NULL);
+#endif
+drop1:
+	free_irq(IRQ_PRCMU_CA_WAKE, NULL);
+drop2:
+	free_irq(IRQ_PRCMU_CA_SLEEP, NULL);
+free_kw6:
+	kthread_stop(shrm->shrm_mod_stuck_kw_task);
+free_kw5:
+	kthread_stop(shrm->shrm_ac_sleep_kw_task);
+free_kw4:
+	kthread_stop(shrm->shrm_ca_wake_kw_task);
+free_kw3:
+	kthread_stop(shrm->shrm_ac_wake_kw_task);
+free_kw2:
+	kthread_stop(shrm->shrm_audio_ch_wr_kw_task);
+free_kw1:
+	kthread_stop(shrm->shrm_common_ch_wr_kw_task);
+	return err;
+}
+
+void shrm_protocol_deinit(struct shrm_dev *shrm)
+{
+	free_irq(IRQ_PRCMU_CA_SLEEP, NULL);
+	free_irq(IRQ_PRCMU_CA_WAKE, NULL);
+	free_irq(IRQ_PRCMU_MODEM_SW_RESET_REQ, NULL);
+	flush_kthread_worker(&shrm->shrm_common_ch_wr_kw);
+	flush_kthread_worker(&shrm->shrm_audio_ch_wr_kw);
+	flush_kthread_worker(&shrm->shrm_ac_wake_kw);
+	flush_kthread_worker(&shrm->shrm_ca_wake_kw);
+	flush_kthread_worker(&shrm->shrm_ac_sleep_kw);
+	flush_kthread_worker(&shrm->shrm_mod_stuck_kw);
+	kthread_stop(shrm->shrm_common_ch_wr_kw_task);
+	kthread_stop(shrm->shrm_audio_ch_wr_kw_task);
+	kthread_stop(shrm->shrm_ac_wake_kw_task);
+	kthread_stop(shrm->shrm_ca_wake_kw_task);
+	kthread_stop(shrm->shrm_ac_sleep_kw_task);
+	kthread_stop(shrm->shrm_mod_stuck_kw_task);
+	modem_put(shrm->modem);
+}
+
+int get_ca_wake_req_state(void)
+{
+	return ((atomic_read(&ac_sleep_disable_count) > 0) ||
+			modem_get_usage(shm_dev->modem));
+}
+
+irqreturn_t ca_wake_irq_handler(int irq, void *ctrlr)
+{
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* initialize the FIFO Variables */
+	if (boot_state == BOOT_INIT)
+		shrm_fifo_init(shrm);
+
+	dev_dbg(shrm->dev, "Inside ca_wake_irq_handler\n");
+
+	/* Clear the interrupt */
+	writel((1 << GOP_CA_WAKE_REQ_BIT),
+				shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+
+	/* send ca_wake_ack_interrupt to CMU */
+	writel((1 << GOP_CA_WAKE_ACK_BIT),
+		shrm->intr_base + GOP_SET_REGISTER_BASE);
+
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+
+irqreturn_t ac_read_notif_0_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+	/* Cancel the modem stuck timer */
+	spin_lock_irqsave(&start_timer_lock, flags);
+	hrtimer_cancel(&mod_stuck_timer_0);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (atomic_read(&fifo_full)) {
+		atomic_set(&fifo_full, 0);
+		hrtimer_cancel(&fifo_full_timer);
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	shrm_ac_read_0_tasklet.data = (unsigned long)shrm;
+	tasklet_schedule(&shrm_ac_read_0_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_COMMON_AC_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ac_read_notif_1_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN+\n", __func__);
+	/* Cancel the modem stuck timer */
+	spin_lock_irqsave(&start_timer_lock, flags);
+	hrtimer_cancel(&mod_stuck_timer_1);
+	spin_unlock_irqrestore(&start_timer_lock, flags);
+	if (atomic_read(&fifo_full)) {
+		atomic_set(&fifo_full, 0);
+		hrtimer_cancel(&fifo_full_timer);
+	}
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	shrm_ac_read_1_tasklet.data = (unsigned long)shrm;
+	tasklet_schedule(&shrm_ac_read_1_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_AUDIO_AC_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_0_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	tasklet_schedule(&shrm_ca_0_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+				&shm_dev->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1 << GOP_COMMON_CA_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ca_msg_pending_notif_1_irq_handler(int irq, void *ctrlr)
+{
+	unsigned long flags;
+	struct shrm_dev *shrm = ctrlr;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return IRQ_NONE;
+	}
+
+	tasklet_schedule(&shrm_ca_1_tasklet);
+
+	local_irq_save(flags);
+	preempt_disable();
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+
+	if (!get_host_accessport_val()) {
+		dev_err(shrm->dev, "%s: host_accessport is low\n", __func__);
+		queue_kthread_work(&shrm->shrm_mod_stuck_kw,
+				&shrm->shrm_mod_reset_req);
+		preempt_enable();
+		local_irq_restore(flags);
+		return IRQ_NONE;
+	}
+	/* Clear the interrupt */
+	writel((1<<GOP_AUDIO_CA_MSG_PENDING_NOTIFICATION_BIT),
+			shrm->intr_base+GOP_CLEAR_REGISTER_BASE);
+	preempt_enable();
+	local_irq_restore(flags);
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return IRQ_HANDLED;
+
+}
+
+/**
+ * shrm_write_msg() - write message to shared memory
+ * @shrm:	pointer to the shrm device information structure
+ * @l2_header:	L2 header
+ * @addr:	pointer to the message
+ * @length:	length of the message to be written
+ *
+ * This function is called from net or char interface driver write operation.
+ * Prior to calling this function the message is copied from the user space
+ * buffer to the kernel buffer. This function based on the l2 header routes
+ * the message to the respective channel and FIFO. Then makes a call to the
+ * fifo write function where the message is written to the physical device.
+ */
+int shrm_write_msg(struct shrm_dev *shrm, u8 l2_header,
+					void *addr, u32 length)
+{
+	u8 channel = 0;
+	int ret, i;
+	u8 *temp;
+
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (boot_state != BOOT_DONE) {
+		dev_err(shrm->dev,
+			"error:after boot done  call this fn, L2Header = %d\n",
+			l2_header);
+		dev_err(shrm->dev, "packet not sent, modem in reset");
+		temp = (u8 *)addr;
+		for (i = 0; i < length; i++)
+			dev_dbg(shrm->dev, "data[%d]=%02x\t", i, temp[i]);
+		dev_dbg(shrm->dev, "\n");
+		/*
+		 * If error is returned then phonet tends to resend the msg
+		 * this will lead to the msg bouncing to and fro between
+		 * phonet and shrm, hence dont return error.
+		*/
+		ret = 0;
+		goto out;
+	}
+
+	if ((l2_header == L2_HEADER_ISI) ||
+			(l2_header == L2_HEADER_RPC) ||
+			(l2_header == L2_HEADER_SECURITY) ||
+			(l2_header == L2_HEADER_COMMON_SIMPLE_LOOPBACK) ||
+			(l2_header == L2_HEADER_COMMON_ADVANCED_LOOPBACK) ||
+			(l2_header == L2_HEADER_CIQ) ||
+			(l2_header == L2_HEADER_RTC_CALIBRATION)) {
+		channel = 0;
+		if (shrm_common_tx_state == SHRM_SLEEP_STATE)
+			shrm_common_tx_state = SHRM_PTR_FREE;
+		else if (shrm_common_tx_state == SHRM_IDLE)
+			shrm_common_tx_state = SHRM_PTR_FREE;
+
+	} else if ((l2_header == L2_HEADER_AUDIO) ||
+			(l2_header == L2_HEADER_AUDIO_SIMPLE_LOOPBACK) ||
+			(l2_header == L2_HEADER_AUDIO_ADVANCED_LOOPBACK)) {
+		if (shrm_audio_tx_state == SHRM_SLEEP_STATE)
+			shrm_audio_tx_state = SHRM_PTR_FREE;
+		else if (shrm_audio_tx_state == SHRM_IDLE)
+			shrm_audio_tx_state = SHRM_PTR_FREE;
+
+		channel = 1;
+	} else {
+		ret = -ENODEV;
+		goto out;
+	}
+	ret = shrm_write_msg_to_fifo(shrm, channel, l2_header, addr, length);
+	if (ret < 0) {
+		dev_err(shrm->dev, "write message to fifo failed\n");
+		if (ret == -EAGAIN) {
+			if (!atomic_read(&fifo_full)) {
+				/* Start a timer so as to handle this gently */
+				atomic_set(&fifo_full, 1);
+				hrtimer_start(&fifo_full_timer, ktime_set(
+						FIFO_FULL_TIMEOUT, 0),
+						HRTIMER_MODE_REL);
+			}
+		}
+		return ret;
+	}
+	/*
+	 * notify only if new msg copied is the only unread one
+	 * otherwise it means that reading process is ongoing
+	 */
+	if (is_the_only_one_unread_message(shrm, channel, length)) {
+
+		/* Send Message Pending Noitication to CMT */
+		if (channel == 0)
+			queue_kthread_work(&shrm->shrm_common_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_0);
+		else
+			queue_kthread_work(&shrm->shrm_audio_ch_wr_kw,
+					&shrm->send_ac_msg_pend_notify_1);
+
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+	return 0;
+
+out:
+	return ret;
+}
+
+void ca_msg_read_notification_0(struct shrm_dev *shrm)
+{
+	unsigned long flags;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_ca_msg_0_read_notif_send() == 0) {
+		update_ca_common_shared_rptr(shrm);
+
+		local_irq_save(flags);
+		preempt_disable();
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+
+		if (!get_host_accessport_val()) {
+			dev_err(shrm->dev, "%s: host_accessport is low\n",
+					__func__);
+			queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+		/* Trigger CaMsgReadNotification to CMU */
+		writel((1 << GOP_COMMON_CA_READ_NOTIFICATION_BIT),
+			shrm->intr_base + GOP_SET_REGISTER_BASE);
+		preempt_enable();
+		local_irq_restore(flags);
+		set_ca_msg_0_read_notif_send(1);
+		shrm_common_rx_state = SHRM_PTR_BUSY;
+	}
+
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+void ca_msg_read_notification_1(struct shrm_dev *shrm)
+{
+	unsigned long flags;
+	dev_dbg(shrm->dev, "%s IN\n", __func__);
+
+	if (get_ca_msg_1_read_notif_send() == 0) {
+		update_ca_audio_shared_rptr(shrm);
+
+		local_irq_save(flags);
+		preempt_disable();
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+
+		if (!get_host_accessport_val()) {
+			dev_err(shrm->dev, "%s: host_accessport is low\n",
+					__func__);
+			queue_kthread_work(&shm_dev->shrm_mod_stuck_kw,
+					&shm_dev->shrm_mod_reset_req);
+			preempt_enable();
+			local_irq_restore(flags);
+			return;
+		}
+		/* Trigger CaMsgReadNotification to CMU */
+		writel((1<<GOP_AUDIO_CA_READ_NOTIFICATION_BIT),
+			shrm->intr_base+GOP_SET_REGISTER_BASE);
+		preempt_enable();
+		local_irq_restore(flags);
+		set_ca_msg_1_read_notif_send(1);
+		shrm_audio_rx_state = SHRM_PTR_BUSY;
+	}
+	dev_dbg(shrm->dev, "%s OUT\n", __func__);
+}
+
+/**
+ * receive_messages_common - receive common channnel msg from
+ * CMT(Cellular Mobile Terminal)
+ * @shrm:	pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the respective(ISI, RPC, SECURIT) queue
+ * based on the message l2 header.
+ */
+void receive_messages_common(struct shrm_dev *shrm)
+{
+	u8 l2_header;
+	u32 len;
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return;
+	}
+
+	l2_header = read_one_l2msg_common(shrm, recieve_common_msg, &len);
+	/* Send Recieve_Call_back to Upper Layer */
+	if (!rx_common_handler) {
+		dev_err(shrm->dev, "common_rx_handler is Null\n");
+		BUG();
+	}
+	(*rx_common_handler)(l2_header, &recieve_common_msg, len,
+					shrm);
+	/* SendReadNotification */
+	ca_msg_read_notification_0(shrm);
+
+	while (read_remaining_messages_common()) {
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			return;
+		}
+
+		l2_header = read_one_l2msg_common(shrm, recieve_common_msg,
+								&len);
+		/* Send Recieve_Call_back to Upper Layer */
+		(*rx_common_handler)(l2_header,
+					&recieve_common_msg, len,
+					shrm);
+	}
+}
+
+/**
+ * receive_messages_audio() - receive audio message from CMT
+ * @shrm:	pointer to shrm device information structure
+ *
+ * The messages sent from CMT to APE are written to the respective FIFO
+ * and an interrupt is triggered by the CMT. This ca message pending
+ * interrupt calls this function. This function sends a read notification
+ * acknowledgement to the CMT and calls the common channel receive handler
+ * where the messsage is copied to the audio queue.
+ */
+void receive_messages_audio(struct shrm_dev *shrm)
+{
+	u8 l2_header;
+	u32 len;
+
+	if (check_modem_in_reset()) {
+		dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+				__func__);
+		return;
+	}
+
+	l2_header = read_one_l2msg_audio(shrm, recieve_audio_msg, &len);
+	/* Send Recieve_Call_back to Upper Layer */
+
+	if (!rx_audio_handler) {
+		dev_crit(shrm->dev, "audio_rx_handler is Null\n");
+		BUG();
+	}
+	(*rx_audio_handler)(l2_header, &recieve_audio_msg,
+					len, shrm);
+
+	/* SendReadNotification */
+	ca_msg_read_notification_1(shrm);
+	while (read_remaining_messages_audio())	{
+		if (check_modem_in_reset()) {
+			dev_err(shrm->dev, "%s:Modem state reset or unknown.\n",
+					__func__);
+			return;
+		}
+
+		l2_header = read_one_l2msg_audio(shrm,
+						recieve_audio_msg, &len);
+		/* Send Recieve_Call_back to Upper Layer */
+		(*rx_audio_handler)(l2_header,
+					&recieve_audio_msg, len,
+					shrm);
+	}
+}
+
+u8 get_boot_state()
+{
+	return boot_state;
+}
-- 
1.7.4.3

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox