* Re: [PATCH 3/14] nes: connection manager routines
From: Jeff Garzik @ 2007-08-08 1:46 UTC (permalink / raw)
To: ggrundstrom; +Cc: rdreier, ewg, netdev
In-Reply-To: <200708080050.l780oGxo004694@neteffect.com>
ggrundstrom@neteffect.com wrote:
> +atomic_t cm_connects;
> +atomic_t cm_accepts;
> +atomic_t cm_disconnects;
> +atomic_t cm_closes;
> +atomic_t cm_connecteds;
> +atomic_t cm_connect_reqs;
> +atomic_t cm_rejects;
do you really want to take the hit of a LOCK prefix each time you
increment a stat???
> +static struct nes_cm_event *create_event(struct nes_cm_node *node_p,
> + enum nes_cm_event_type type)
> +{
> + struct nes_cm_event *event_p;
> +
> + if(!node_p->cm_id)
> + return NULL;
> +
> + /* allocate an empty event */
> + event_p = (struct nes_cm_event *)kzalloc(sizeof(struct nes_cm_event),
> + GFP_ATOMIC);
kill pointless cast from void*
> + if (!event_p)
> + return(NULL);
return is not a function. remove the parens.
> + event_p->type = type;
> + event_p->node_p = node_p;
> + event_p->cm_info.rem_addr = node_p->rem_addr;
> + event_p->cm_info.loc_addr = node_p->loc_addr;
> + event_p->cm_info.rem_port = node_p->rem_port;
> + event_p->cm_info.loc_port = node_p->loc_port;
> + event_p->cm_info.cm_id = node_p->cm_id;
> +
> + dprintk("%s[%u] Created event_p=%p, type=%u, dst_addr=%08x[%x], src_addr=%08x[%x]\n",
> + __FUNCTION__, __LINE__, event_p, type,
> + event_p->cm_info.loc_addr, event_p->cm_info.loc_port,
> + event_p->cm_info.rem_addr, event_p->cm_info.rem_port);
these dprintk's make the code far more unreadable than it should be.
these should be cleaned up.
> + nes_cm_post_event(event_p);
> + return(event_p);
return is not a function, remove parens
> +int send_mpa_request(struct nes_cm_node *node_p)
> +{
> + struct sk_buff *skb_p;
> + int ret;
> +
> + skb_p = get_free_pkt(node_p);
> + if (!skb_p) {
> + dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",
> + __FILE__, __FUNCTION__, __LINE__);
> + return (-1);
> + }
> +
> + /* send an MPA Request frame */
> + form_cm_frame(skb_p, node_p, NULL, 0, &node_p->mpa_frame_p,
> + node_p->mpa_frame_size, SET_ACK);
> +
> + ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 1);
> + if (ret < 0) {
> + return (ret);
> + }
remove braces around single C statements
> + dprintk("%s[%u] -- \n", __FUNCTION__, __LINE__);
> + return (0);
* remove all the "_p" suffixes. the kernel is not the place to start
approaching Hungarian notation
* return is not a function
> + * recv_mpa - process a received TCP pkt, we are expecting an
> + * IETF MPA frame
> + */
> +static int parse_mpa(struct nes_cm_node *node_p, u8 *buffer, u32 len)
'buffer' should be void* not u8*
> +{
> + struct ietf_mpa_frame *mpa_frame_p;
> +
> + dprintk("%s[%u] Enter, node_p=%p\n", __FUNCTION__, __LINE__, node_p);
> + nes_dump_mem(buffer, len);
> +
> + /* assume req frame is in tcp data payload */
> + if (len < sizeof(struct ietf_mpa_frame)) {
> + dprintk("The received ietf buffer was too small (%x)\n", len);
> + return (-1);
return is not a function
> + }
> +
> + mpa_frame_p = (struct ietf_mpa_frame *)buffer;
kill pointless cast, once 'buffer' type is fixed
> + node_p->mpa_frame_size = (u32)ntohs(mpa_frame_p->priv_data_len);
kill pointless cast
> + if (node_p->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
> + dprintk("The received ietf buffer was not right complete (%x + %x != %x)\n",
> + node_p->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
> + return (-1);
> + }
> +
> + dprintk("%s[%u] -- recvd MPA Frame - with private data len = %u\n",
> + __FILE__, __LINE__, node_p->mpa_frame_size);
> +
> + /* copy entire MPA frame to our node's frame */
> + memcpy(node_p->mpa_frame_b, buffer + sizeof(struct ietf_mpa_frame),
> + node_p->mpa_frame_size);
> + nes_dump_mem(&node_p->mpa_frame_p, node_p->mpa_frame_size);
> + dprintk("%s:%s[%u] -- Exit\n", __FILE__, __FUNCTION__, __LINE__);
> +
> + return(0);
> +}
return is not a function
> + * handle_exception_pkt - process an exception packet.
> + * We have been in a TSA state, and we have now received SW
> + * TCP/IP traffic should be a FIN request or IP pkt with options
> + */
> +static int handle_exception_pkt(struct nes_cm_node *node_p,
> + struct sk_buff *skb_p)
> +{
> + int ret = 0;
> + struct tcphdr *tcphdr_p = skb_p->h.th;
kill all "_p" suffixes
> + /* first check to see if this a FIN pkt */
> + if (tcphdr_p->fin) {
> + /* we need to ACK the FIN request */
> + send_ack(node_p);
> +
> + /* check which side we are (client/server) and set next state accordingly */
> + if (node_p->tcp_cntxt.client)
> + node_p->state = NES_CM_STATE_CLOSING;
> + else {
> + /* we are the server side */
> + node_p->state = NES_CM_STATE_CLOSE_WAIT;
> + /* since this is a self contained CM we don't wait for */
> + /* an APP to close us, just send final FIN immediately */
> + ret = send_fin(node_p, NULL);
> + node_p->state = NES_CM_STATE_LAST_ACK;
> + }
> + } else {
> + ret = -EINVAL;
why is this TCP management in this driver?
> + * form_cm_frame - get a free packet and build empty frame Use
> + * node info to build.
> + */
> +struct sk_buff *form_cm_frame(struct sk_buff *skb_p, struct nes_cm_node *node_p,
> + void *options, u32 optionsize, void *data, u32 datasize, u8 flags)
> +{
> + struct tcphdr *tcphdr_p;
> + struct iphdr *iphdr_p;
> + struct ethhdr *ethhdr_p;
> + u8 *buf_p;
'buf' should be void* not u8*
> + u16 packetsize = sizeof(*iphdr_p);
kill suffixes
> + packetsize += sizeof(*tcphdr_p);
> + packetsize += optionsize + datasize;
> +
> + memset(skb_p->data, 0x00, ETH_HLEN + sizeof(*iphdr_p) + sizeof(*tcphdr_p));
> +
> + skb_p->len = 0;
why? are you reusing or abusing the skb somehow?
> + buf_p = skb_put(skb_p, packetsize + ETH_HLEN);
> +
> + ethhdr_p = (struct ethhdr *) buf_p;
> + buf_p += ETH_HLEN;
> +
> + iphdr_p = skb_p->nh.iph = (struct iphdr *)buf_p;
> + buf_p += sizeof(*iphdr_p);
> +
> + tcphdr_p = skb_p->h.th = (struct tcphdr *) buf_p;
> + buf_p += sizeof(*tcphdr_p);
> +
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
> + skb_p->ip_summed = CHECKSUM_HW;
> +#else
> + skb_p->ip_summed = CHECKSUM_PARTIAL;
> +#endif
> + skb_p->protocol = ntohs(0x800);
> + skb_p->data_len = 0;
> + skb_p->mac.raw = skb_p->data;
> + skb_p->mac_len = ETH_HLEN;
> +
> + memcpy(ethhdr_p->h_dest, node_p->rem_mac, ETH_ALEN);
> + memcpy(ethhdr_p->h_source, node_p->loc_mac, ETH_ALEN);
> + ethhdr_p->h_proto = htons(0x0800);
> +
> + iphdr_p->version = IPVERSION;
> + iphdr_p->ihl = 5; /* 5 * 4Byte words, IP headr len */
> + iphdr_p->tos = 0;
> + iphdr_p->tot_len = htons(packetsize);
> + iphdr_p->id = htons(++node_p->tcp_cntxt.loc_id);
> +
> + iphdr_p->frag_off = ntohs(0x4000);
> + iphdr_p->ttl = 0x40;
> + iphdr_p->protocol= 0x06; /* IPPROTO_TCP */
> +
> + iphdr_p->saddr = htonl(node_p->loc_addr);
> + iphdr_p->daddr = htonl(node_p->rem_addr);
> +
> + tcphdr_p->source = htons(node_p->loc_port);
> + tcphdr_p->dest = htons(node_p->rem_port);
> + tcphdr_p->seq = htonl(node_p->tcp_cntxt.loc_seq_num);
> +
> + if (flags & SET_ACK) {
> + node_p->tcp_cntxt.loc_ack_num = node_p->tcp_cntxt.rcv_nxt;
> + tcphdr_p->ack_seq = htonl(node_p->tcp_cntxt.loc_ack_num);
> + tcphdr_p->ack = 1;
> + } else
> + tcphdr_p->ack_seq = 0;
> +
> + if (flags & SET_SYN) {
> + node_p->tcp_cntxt.loc_seq_num ++;
> + tcphdr_p->syn = 1;
> + } else
> + node_p->tcp_cntxt.loc_seq_num += datasize; /* data (no headers) */
> +
> + dprintk("%s[%u] Local seq # now %x\n", __FUNCTION__, __LINE__,
> + node_p->tcp_cntxt.loc_seq_num);
> + if (flags & SET_FIN)
> + tcphdr_p->fin = 1;
> +
> + if (flags & SET_RST)
> + tcphdr_p->rst = 1;
> +
> + tcphdr_p->doff = (u16) ((sizeof(*tcphdr_p) + optionsize + 3)>> 2);
> + tcphdr_p->window = htons(node_p->tcp_cntxt.rcv_wnd);
> + tcphdr_p->urg_ptr = 0;
> + if (optionsize)
> + memcpy(buf_p, options, optionsize);
> + buf_p += optionsize;
> + if (datasize)
> + memcpy(buf_p, data, datasize);
> +
> + skb_shinfo(skb_p)->nr_frags = 0;
> +
> + return(skb_p);
creating TCP packets by hand?
> +static void dump_pkt(struct sk_buff *skb_p)
> +{
> + u8 *pkt_p;
> +
> + if (!skb_p)
> + return;
> +
> + pkt_p = (u8 *)skb_p->data;
> + /* dprintk("skb_p->head=%p, data=%p, tail=%p, end=%p,"
> + "skb_p->len=%u, data_len=%u\n",
> + skb_p->head, skb_p->data, skb_p->tail, skb_p->end,
> + skb_p->len, skb_p->data_len);
> + */
> + nes_dump_mem(pkt_p, skb_p->len);
> +
> + return;
> +}
> +
> +
> +/**
> + * print_core - dump a cm core
> + */
> +static void print_core(struct nes_cm_core *core_p)
> +{
> + dprintk("---------------------------------------------\n");
> + dprintk("CM Core -- (core_p = %p )\n", core_p);
> + if (!core_p)
> + return;
> + dprintk("---------------------------------------------\n");
> + dprintk("Session ID : %u \n", atomic_read(&core_p->session_id));
> +
> + dprintk("State : %u \n", core_p->state);
> +
> + dprintk("Tx Free cnt : %u \n", skb_queue_len(&core_p->tx_free_list));
> + dprintk("Listen Nodes : %u \n", atomic_read(&core_p->listen_node_cnt));
> + dprintk("Active Nodes : %u \n", atomic_read(&core_p->node_cnt));
> +
> + dprintk("core_p : %p \n", core_p);
> +
> + dprintk("-------------- end core ---------------\n");
> + return;
kill all pointless "return;" at the end of functions
> +int schedule_nes_timer(struct nes_cm_node *node_p, struct sk_buff *skb_p,
> + enum nes_timer_type type, int send_retrans)
> +{
> + unsigned long flags;
> + struct nes_cm_core *core_p;
> + struct nes_timer_entry *new_send;
> + int ret = 0;
> + u32 was_timer_set;
> +
> + new_send = kzalloc(sizeof(struct nes_timer_entry), GFP_ATOMIC);
> + if(!new_send)
> + return -1;
> + /* new_send->timetosend = currenttime */
> + new_send->retrycount = NES_DEFAULT_RETRYS;
> + new_send->retranscount = NES_DEFAULT_RETRANS;
> + new_send->skb = skb_p;
> + new_send->timetosend = jiffies;
> + new_send->type = type;
> + new_send->netdev = node_p->netdev_p;
> + new_send->send_retrans = send_retrans;
> +
> + if(type == NES_TIMER_TYPE_CLOSE) {
> + dprintk("Scheduling Close: node_p = %p, new_send = %p.\n", node_p, new_send);
> + new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
> + spin_lock_irqsave(&node_p->recv_list_lock, flags);
> + list_add_tail(&new_send->list, &node_p->recv_list);
> + spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
> + }
> +
> + if(type == NES_TIMER_TYPE_SEND) {
> + dprintk("Sending Packet %p:\n", new_send);
> + new_send->seq_num = htonl(skb_p->h.th->seq);
> + dump_pkt(skb_p);
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + list_add_tail(&new_send->list, &node_p->retrans_list);
> + spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
> + }
> + if(type == NES_TIMER_TYPE_RECV) {
> + new_send->seq_num = htonl(skb_p->h.th->seq);
> + spin_lock_irqsave(&node_p->recv_list_lock, flags);
> + list_add_tail(&new_send->list, &node_p->recv_list);
> + spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
> + }
the lack of 'else' keywords implies these more than one of these
conditions can occur simultaneously. If so, don't you think it's quite
expensive to grab and release all these locks?
> + core_p = node_p->core_p;
> +
> + was_timer_set = timer_pending(&core_p->tcp_timer);
> +
> + if(!was_timer_set || time_before(new_send->timetosend,
> + core_p->tcp_timer.expires)){
> + if(was_timer_set) {
> + del_timer(&core_p->tcp_timer);
> + }
single C statement: remove braces
> + core_p->tcp_timer.expires = new_send->timetosend;
> +
> + add_timer(&core_p->tcp_timer);
> + }
> + return(ret);
return not a function
> +/**
> + * nes_cm_timer_tick
> + */
> +void nes_cm_timer_tick(unsigned long pass)
this seems like a poor design. AFAICS you should be using delayed
workqueues or something other than a timer.
> + unsigned long flags, qplockflags;
> + unsigned long nexttimeout = jiffies + NES_LONG_TIME;
> + struct iw_cm_id *cm_id;
> + struct nes_cm_node *node_p;
> + struct nes_timer_entry *send_entry, *recv_entry;
> + struct list_head *list_p_core, *list_p_core_temp, *list_p_node_temp, *list_p_node;
> + struct nes_cm_core *core_p = g_cm_core_p;
> + struct nes_qp *nesqp;
> + u32 settimer = 0;
> + int ret = NETDEV_TX_OK;
> +
> + list_for_each_safe(list_p_node, list_p_core_temp, &core_p->connected_nodes) {
> + node_p = container_of(list_p_node, struct nes_cm_node, list);
> + spin_lock_irqsave(&node_p->recv_list_lock, flags);
> + list_for_each_safe(list_p_core, list_p_node_temp, &node_p->recv_list) {
> + recv_entry = container_of(list_p_core, struct nes_timer_entry, list);
> + if ((time_after(recv_entry->timetosend, jiffies)) &&
> + (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
> + if(nexttimeout > recv_entry->timetosend || !settimer) {
> + nexttimeout = recv_entry->timetosend;
> + settimer = 1;
> + }
> + continue;
> + }
> + list_del(&recv_entry->list);
> + cm_id = node_p->cm_id;
> + spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
> + if(recv_entry->type == NES_TIMER_TYPE_CLOSE) {
> + nesqp = (struct nes_qp *)recv_entry->skb;
> + cm_id->rem_ref(cm_id);
> + spin_lock_irqsave(&nesqp->lock, qplockflags);
> + if (nesqp->cm_id) {
> + dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
> + " with something to do!!! ******\n",
> + __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
> + nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
> + nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
> + nesqp->ibqp_state = IB_QPS_ERR;
> + spin_unlock_irqrestore(&nesqp->lock, qplockflags);
> + nes_cm_disconn(nesqp);
> + } else {
> + spin_unlock_irqrestore(&nesqp->lock, qplockflags);
> + dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
> + " with nothing to do!!! ******\n",
> + __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
> + nes_rem_ref(&nesqp->ibqp);
> + }
> + }
> + else if(recv_entry->type == NES_TIMER_TYPE_RECV) {
> + dprintk("Processing Packet (%p):\n", recv_entry->skb->data);
> + dump_pkt(recv_entry->skb);
> + process_packet(node_p, recv_entry->skb, core_p);
> + dev_kfree_skb_any(recv_entry->skb);
> + }
> + kfree(recv_entry);
> + spin_lock_irqsave(&node_p->recv_list_lock, flags);
> + }
> + spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
> +
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + list_for_each_safe(list_p_core, list_p_node_temp, &node_p->retrans_list) {
> + send_entry = container_of(list_p_core, struct nes_timer_entry, list);
> + if(time_after(send_entry->timetosend, jiffies)) {
> + if(nexttimeout > send_entry->timetosend || !settimer) {
> + nexttimeout = send_entry->timetosend;
> + settimer = 1;
> + }
> + continue;
> + }
> + list_del(&send_entry->list);
> + spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
> + if(send_entry->type == NES_TIMER_NODE_CLEANUP){
> + dprintk("!send - %p-> next/prev=%p,%p, tts=%lx, skb=%p, type=%x,"
> + " retry=%x, retrans=%x, context=%x, seq=%x\n",
> + send_entry, send_entry->list.next, send_entry->list.prev,
> + send_entry->timetosend, send_entry->skb, send_entry->type,
> + send_entry->retrycount, send_entry->retranscount,
> + send_entry->context, send_entry->seq_num);
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + continue;
> + }
> + if(send_entry->seq_num < node_p->tcp_cntxt.rem_ack_num ||
> + node_p->accelerated) {
> + dev_kfree_skb_any(send_entry->skb);
> + kfree(send_entry);
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + continue;
> + }
> +
> + if(!send_entry->retranscount || !send_entry->retrycount) {
> + dev_kfree_skb_any(send_entry->skb);
> + kfree(send_entry);
> + create_event(node_p, NES_CM_EVENT_ABORTED);
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + continue;
> + }
> + atomic_inc(&send_entry->skb->users);
> + ret = nes_nic_cm_xmit(send_entry->skb, node_p->netdev_p);
> + if(ret != NETDEV_TX_OK) {
> + atomic_dec(&send_entry->skb->users);
> + send_entry->retrycount--;
> + nexttimeout = jiffies + NES_SHORT_TIME;
> + settimer = 1;
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + list_add(&send_entry->list, &node_p->retrans_list);
> + break;
> + }
> + dprintk("Packet Sent:\n");
> + dump_pkt(send_entry->skb);
> + if(send_entry->send_retrans) {
> + send_entry->retranscount--;
> + send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
> + if(nexttimeout > send_entry->timetosend || !settimer) {
> + nexttimeout = send_entry->timetosend;
> + settimer = 1;
> + }
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + list_add(&send_entry->list, &node_p->retrans_list);
> + continue;
> + }
> + else {
> + dev_kfree_skb_any(send_entry->skb);
> + kfree(send_entry);
> + spin_lock_irqsave(&node_p->retrans_list_lock, flags);
> + continue;
> + }
> + }
> + spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
> +
> + if(ret != NETDEV_TX_OK)
> + break;
> + }
> +
> + if(settimer)
> + {
> + if(timer_pending(&core_p->tcp_timer)) {
> + del_timer(&core_p->tcp_timer);
> + }
> + core_p->tcp_timer.expires = nexttimeout;
> + add_timer(&core_p->tcp_timer);
are you reinventing mod_timer() ?
I stopped reviewing here. Please make all the style changes so that we
can review your driver in depth.
All the debug-print code makes the driver highly unreadable. Most of
that should go away now that you are moving towards a kernel submission.
Jeff
^ permalink raw reply
* Re: Please pull 'libertas-upstream' branch of wireless-2.6
From: John W. Linville @ 2007-08-08 0:50 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-wireless, netdev
In-Reply-To: <46B8F0C3.6030409@garzik.org>
On Tue, Aug 07, 2007 at 06:22:59PM -0400, Jeff Garzik wrote:
> John W. Linville wrote:
> >Got a big patch bomb from the libertas guys. I tried to cherry-pick
> >some of the fixes for 2.6.23, but they either were fixes to problems
> >in new code or all the code cleanups made them difficult for me to
> >intelligently backport.
> >
> >So, this is intended for 2.6.24...
> >
> >---
> >
> >The following changes since commit
> >d4ac2477fad0f2680e84ec12e387ce67682c5c13:
> > Linus Torvalds (1):
> > Linux 2.6.23-rc2
> >
> >are available in the git repository at:
> >
> > git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git
> > libertas-upstream
>
> This is missing the patch. I looked at it locally, but please do send a
> patch for review with each push, no matter how big.
Ooops, sorry! I apologoze for the oversight.
> pulled into #upstream
Thanks!
John
--
John W. Linville
linville@tuxdriver.com
^ permalink raw reply
* Re: [PATCH] improved xfrm_audit_log() patch
From: David Miller @ 2007-08-08 1:32 UTC (permalink / raw)
To: latten; +Cc: netdev
In-Reply-To: <200708022056.l72KulGS019506@faith.austin.ibm.com>
From: Joy Latten <latten@austin.ibm.com>
Date: Thu, 2 Aug 2007 15:56:47 -0500
> @@ -426,10 +426,15 @@ struct xfrm_audit
> };
>
> #ifdef CONFIG_AUDITSYSCALL
> -extern void xfrm_audit_log(uid_t auid, u32 secid, int type, int result,
> - struct xfrm_policy *xp, struct xfrm_state *x);
> +extern void xfrm_audit_log(struct xfrm_audit audit_info, int result,
> + __be32 flowid, struct xfrm_policy *xp,
> + struct xfrm_state *x, char *buf);
Passing audit_info as an aggregate argument puts them into
previous argument registers, or if they are not enough it
goes either partially of wholly onto the stack, depending
upon architecture.
In fact you've made the argument register usage worse than
in your previous revision. :-/
Perhaps you meant to pass "struct xfrm_audit *" instead?
^ permalink raw reply
* [PATCH 14/14] nes: kernel build infrastructure
From: ggrundstrom @ 2007-08-08 1:25 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Makefile kernel build file.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/Makefile
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/Makefile 2007-08-06 20:09:04.000000000 -0500
@@ -0,0 +1,10 @@
+ifdef CONFIG_INFINIBAND_NES_DEBUG
+EXTRA_CFLAGS += -DNES_DEBUG
+endif
+
+EXTRA_CFLAGS += -DNES_MINICM
+
+obj-$(CONFIG_INFINIBAND_NES) += iw_nes.o
+
+iw_nes-objs := nes.o nes_hw.o nes_nic.o nes_utils.o nes_verbs.o nes_cm.o
+
^ permalink raw reply
* [PATCH 13/14] nes: kernel build infrastructure
From: ggrundstrom @ 2007-08-08 1:23 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Kconfig kernel build file.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/Kconfig
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/Kconfig 2007-08-06 20:09:04.000000000 -0500
@@ -0,0 +1,15 @@
+config INFINIBAND_NES
+ tristate "NetEffect RNIC Driver"
+ depends on PCI && INET && INFINIBAND
+ ---help---
+ This is a low-level driver for NetEffect RDMA enabled
+ Network Interface Cards (RNIC).
+
+config INFINIBAND_NES_DEBUG
+ bool "Verbose debugging output"
+ depends on INFINIBAND_NES
+ default n
+ ---help---
+ This option causes the NetEffect RNIC driver to produce debug
+ messages. Select this if you are developing the driver
+ or trying to diagnose a problem.
^ permalink raw reply
* Re: [PATCH] TCP: H-TCP maxRTT estimation at startup
From: David Miller @ 2007-08-08 1:29 UTC (permalink / raw)
To: shemminger; +Cc: doug.leith, netdev
In-Reply-To: <20070803105756.2f41dc25@oldman.hamilton.local>
From: Stephen Hemminger <shemminger@linux-foundation.org>
Date: Fri, 3 Aug 2007 10:57:56 +0100
> Small patch to H-TCP from Douglas Leith.
>
> Fix estimation of maxRTT. The original code ignores rtt measurements
> during slow start (via the check tp->snd_ssthresh < 0xFFFF) yet this
> is probably a good time to try to estimate max rtt as delayed acking
> is disabled and slow start will only exit on a loss which presumably
> corresponds to a maxrtt measurement. Second, the original code (via
> the check htcp_ccount(ca) > 3) ignores rtt data during what it
> estimates to be the first 3 round-trip times. This seems like an
> unnecessary check now that the RCV timestamp are no longer used
> for rtt estimation.
>
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Applied, thanks Stephen.
^ permalink raw reply
* Re: TCP's initial cwnd setting correct?...
From: David Miller @ 2007-08-08 1:28 UTC (permalink / raw)
To: ilpo.jarvinen; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0708061508070.8788@kivilampi-30.cs.helsinki.fi>
From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Mon, 6 Aug 2007 15:37:15 +0300 (EEST)
> @@ -805,13 +805,13 @@ void tcp_update_metrics(struct sock *sk)
> }
> }
>
> -/* Numbers are taken from RFC2414. */
> +/* Numbers are taken from RFC3390. */
> __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
> {
> __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
>
> if (!cwnd) {
> - if (tp->mss_cache > 1460)
> + if (tp->mss_cache >= 2190)
> cwnd = 2;
> else
> cwnd = (tp->mss_cache > 1095) ? 3 : 4;
I remember suggesting something similar about 5 or 6 years
ago and Alexey Kuznetsov at the time explained the numbers
which are there and why they should not be changed.
I forget the reasons though, and I'll try to do the research.
These numbers have been like this forever, FWIW.
^ permalink raw reply
* [PATCH 12/14] nes: OpenFabrics kernel verb includes
From: ggrundstrom @ 2007-08-08 1:21 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
OpenFabrics kernel verbs provider structures and defines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_verbs.h
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_verbs.h 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2006 NetEffect, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_VERBS_H
+#define NES_VERBS_H
+
+struct nes_device;
+
+#define NES_MAX_USER_DB_REGIONS 4096
+#define NES_MAX_USER_WQ_REGIONS 4096
+
+struct nes_ucontext {
+ struct ib_ucontext ibucontext;
+ struct nes_device *nesdev;
+ unsigned long mmap_wq_offset;
+ unsigned long mmap_cq_offset; /* to be removed */
+ int index; /* rnic index (minor) */
+ unsigned long allocated_doorbells[BITS_TO_LONGS(NES_MAX_USER_DB_REGIONS)];
+ u16 mmap_db_index[NES_MAX_USER_DB_REGIONS];
+ u16 first_free_db;
+ unsigned long allocated_wqs[BITS_TO_LONGS(NES_MAX_USER_WQ_REGIONS)];
+ struct nes_qp * mmap_nesqp[NES_MAX_USER_WQ_REGIONS];
+ u16 first_free_wq;
+ struct list_head cq_reg_mem_list;
+};
+
+struct nes_pd {
+ struct ib_pd ibpd;
+ u16 pd_id;
+ atomic_t sqp_count;
+ u16 mmap_db_index;
+};
+
+struct nes_mr {
+ union {
+ struct ib_mr ibmr;
+ struct ib_mw ibmw;
+ struct ib_fmr ibfmr;
+ };
+ u16 pbls_used;
+ u8 mode;
+ u8 pbl_4k;
+};
+
+struct nes_hw_pb {
+ u32 pa_low;
+ u32 pa_high;
+};
+
+struct nes_vpbl {
+ dma_addr_t pbl_pbase;
+ struct nes_hw_pb *pbl_vbase;
+};
+
+struct nes_root_vpbl {
+ dma_addr_t pbl_pbase;
+ struct nes_hw_pb *pbl_vbase;
+ struct nes_vpbl *leaf_vpbl;
+};
+
+struct nes_av;
+
+struct nes_cq {
+ struct ib_cq ibcq;
+ struct nes_hw_cq hw_cq;
+ u32 polled_completions;
+ u32 cq_mem_size;
+ spinlock_t lock;
+ u8 virtual_cq;
+ u8 pad[3];
+};
+
+struct nes_wq {
+ spinlock_t lock;
+};
+
+struct iw_cm_id;
+struct ietf_mpa_frame;
+
+struct nes_qp {
+ struct ib_qp ibqp;
+ void * allocated_buffer;
+ struct iw_cm_id *cm_id;
+ struct workqueue_struct *wq;
+ struct work_struct disconn_work;
+ struct socket *ksock;
+ struct nes_cq *nesscq;
+ struct nes_cq *nesrcq;
+ struct nes_pd *nespd;
+ struct ietf_mpa_frame *ietf_frame;
+ dma_addr_t ietf_frame_pbase;
+ wait_queue_head_t state_waitq;
+ unsigned long socket;
+ struct nes_hw_qp hwqp;
+ struct work_struct work;
+ struct work_struct ae_work;
+ enum ib_qp_state ibqp_state;
+ u32 iwarp_state;
+ u32 hte_index;
+ u32 last_aeq;
+ u32 qp_mem_size;
+ atomic_t refcount;
+ u32 mmap_sq_db_index;
+ u32 mmap_rq_db_index;
+ spinlock_t lock;
+ struct nes_qp_context *nesqp_context;
+ dma_addr_t nesqp_context_pbase;
+ wait_queue_head_t kick_waitq;
+ u16 in_disconnect;
+ u16 private_data_len;
+ u8 active_conn;
+ u8 skip_lsmm;
+ u8 user_mode;
+ u8 hte_added;
+ u8 hw_iwarp_state;
+ u8 flush_issued;
+ u8 hw_tcp_state;
+ u8 disconn_pending;
+ void *cm_node_p; /* handle of the node this QP is associated with */
+};
+#endif /* NES_VERBS_H */
^ permalink raw reply
* [PATCH 11/14] nes: OpenFabrics kernel verbs
From: ggrundstrom @ 2007-08-08 1:19 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
OpenFabrics kernel verbs provider routines
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_verbs.c
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_verbs.c 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,3605 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/iw_cm.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "nes.h"
+
+atomic_t mod_qp_timouts;
+atomic_t qps_created;
+extern atomic_t cm_closes;
+atomic_t sw_qps_destroyed;
+
+extern int disable_mpa_crc;
+
+
+/**
+ * nes_alloc_mw
+ */
+static struct ib_mw *nes_alloc_mw(struct ib_pd *ibpd) {
+ unsigned long flags;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_cqp_request *cqp_request;
+ struct nes_mr *nesmr;
+ struct ib_mw *ibmw;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u8 stag_key = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (ret) {
+ return (ERR_PTR(ret));
+ }
+
+ nesmr = kmalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ dprintk("%s: Registering STag 0x%08X, index = 0x%08X\n",
+ __FUNCTION__, stag, stag_index);
+
+ /* Register the region with the adapter */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ kfree(nesmr);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (ERR_PTR(-ENOMEM));
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32( NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_RIGHTS_REMOTE_READ |
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_VA_TO |
+ NES_CQP_STAG_REM_ACC_EN);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
+ cpu_to_le32(nespd->pd_id&0x00007fff);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_STAG_IDX] = cpu_to_le32(stag);
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s: Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ __FUNCTION__, stag, ret, cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ kfree(nesmr);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ if (!ret) {
+ return (ERR_PTR(-ETIME));
+ } else {
+ return (ERR_PTR(-ENOMEM));
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ nesmr->ibmw.rkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MW;
+ ibmw = &nesmr->ibmw;
+ nesmr->pbl_4k = 0;
+ nesmr->pbls_used = 0;
+
+ return (ibmw);
+}
+
+
+/**
+ * nes_dealloc_mw
+ */
+static int nes_dealloc_mw(struct ib_mw *ibmw)
+{
+ struct nes_mr *nesmr = to_nesmw(ibmw);
+ struct nes_vnic *nesvnic = to_nesvnic(ibmw->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ int err = 0;
+ unsigned long flags;
+ int ret;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ /* Deallocate the window with the adapter */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = NES_CQP_DEALLOCATE_STAG;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_STAG_IDX] = ibmw->rkey;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("Waiting for deallocate STag 0x%08X to complete.\n", ibmw->rkey);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("Deallocate STag completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ ret, cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret) {
+ err = -ETIME;
+ } else {
+ err = -EIO;
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ (ibmw->rkey&0x0fffff00) >> 8);
+ kfree(nesmr);
+
+ return (err);
+}
+
+
+/**
+ * nes_bind_mw
+ */
+static int nes_bind_mw(struct ib_qp *ibqp, struct ib_mw *ibmw,
+ struct ib_mw_bind *ibmw_bind)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* struct nes_mr *nesmr = to_nesmw(ibmw); */
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_hw_qp_wqe *wqe;
+ unsigned long flags = 0;
+ u32 head;
+ u32 wqe_misc = 0;
+ u32 qsize;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return (-EINVAL);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.sq_head;
+ qsize = nesqp->hwqp.sq_tail;
+
+ /* Check for SQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+ return (-EINVAL);
+ }
+
+ wqe = &nesqp->hwqp.sq_vbase[head];
+ /* dprintk("%s:processing sq wqe at %p, head = %u.\n", __FUNCTION__, wqe, head); */
+ *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX]) = ibmw_bind->wr_id;
+ *((struct nes_qp **)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX] |= head;
+ wqe_misc = NES_IWARP_SQ_OP_BIND;
+
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+
+ if (ibmw_bind->send_flags & IB_SEND_SIGNALED)
+ wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+
+ if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_WRITE) {
+ wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_WRITE;
+ }
+ if (ibmw_bind->mw_access_flags & IB_ACCESS_REMOTE_READ) {
+ wqe_misc |= NES_CQP_STAG_RIGHTS_REMOTE_READ;
+ }
+
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(wqe_misc);
+ wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_MR_IDX] = cpu_to_le32(ibmw_bind->mr->lkey);
+ wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_MW_IDX] = cpu_to_le32(ibmw->rkey);
+ wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX] =
+ cpu_to_le32(ibmw_bind->length);
+ wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX] = 0;
+ *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX]) =
+ cpu_to_le64(ibmw_bind->addr);
+
+ head++;
+ if (head >= qsize)
+ head = 0;
+
+ nesqp->hwqp.sq_head = head;
+ barrier();
+
+ nes_write32(nesdev->regs + NES_WQE_ALLOC,
+ (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ return (0);
+}
+
+
+/**
+ * nes_alloc_fmr
+ */
+static struct ib_fmr *nes_alloc_fmr(struct ib_pd *ibpd, int ibmr_access_flags,
+ struct ib_fmr_attr *ibfmr_attr)
+{
+ unsigned long flags;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_mr *nesmr;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u8 stag_key = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (ret) {
+ return (ERR_PTR(ret));
+ }
+
+ nesmr = kmalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ nesmr->mode = IWNES_MEMREG_TYPE_FMR;
+ if (ibfmr_attr->max_pages == 1) {
+ /* use zero length PBL */
+ nesmr->pbl_4k = 0;
+ nesmr->pbls_used = 0;
+ } else if (ibfmr_attr->max_pages <= 32) {
+ /* use PBL 256 */
+ nesmr->pbl_4k = 0;
+ nesmr->pbls_used = 1;
+ } else if (ibfmr_attr->max_pages <= 512) {
+ /* use 4K PBLs */
+ nesmr->pbl_4k = 1;
+ nesmr->pbls_used = 1;
+ } else {
+ /* use two level 4K PBLs */
+ /* add support for two level 256B PBLs */
+ nesmr->pbl_4k = 1;
+ nesmr->pbls_used = 1 + (ibfmr_attr->max_pages >> 9) +
+ ((ibfmr_attr->max_pages & 511) ? 1:0);
+ }
+ /* Register the region with the adapter */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ /* track PBL resources */
+ if (nesmr->pbls_used != 0) {
+ if (nesmr->pbl_4k) {
+ if (nesmr->pbls_used > nesadapter->free_4kpbl) {
+ kfree(nesmr);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ } else {
+ nesadapter->free_4kpbl -= nesmr->pbls_used;
+ }
+ } else {
+ if (nesmr->pbls_used > nesadapter->free_256pbl) {
+ kfree(nesmr);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ } else {
+ nesadapter->free_256pbl -= nesmr->pbls_used;
+ }
+ }
+ }
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ kfree(nesmr);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ dprintk("%s: Registering STag 0x%08X, index = 0x%08X\n",
+ __FUNCTION__, stag, stag_index);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(NES_CQP_ALLOCATE_STAG | NES_CQP_STAG_RIGHTS_REMOTE_READ |
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_VA_TO |
+ NES_CQP_STAG_REM_ACC_EN | NES_CQP_STAG_MR |
+ (nesmr->pbl_4k == 1) ? NES_CQP_STAG_PBL_BLK_SIZE : 0);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
+ cpu_to_le32(nespd->pd_id & 0x00007fff);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_STAG_IDX] = cpu_to_le32(stag);
+
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] =
+ cpu_to_le32((nesmr->pbls_used > 1) ?
+ (nesmr->pbls_used-1) : nesmr->pbls_used);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s: Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ __FUNCTION__, stag, ret, cqp_request->major_code, cqp_request->minor_code);
+
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ kfree(nesmr);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ if (!ret) {
+ return (ERR_PTR(-ETIME));
+ } else {
+ return (ERR_PTR(-EIO));
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ nesmr->ibfmr.lkey = stag;
+ nesmr->ibfmr.rkey = stag;
+
+ return (&nesmr->ibfmr);
+}
+
+
+/**
+ * nes_dealloc_fmr
+ */
+static int nes_dealloc_fmr(struct ib_fmr *ibfmr)
+{
+ struct nes_mr *nesmr = to_nesfmr(ibfmr);
+ struct nes_mr temp_nesmr = *nesmr;
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ temp_nesmr.ibmw.device = ibfmr->device;
+ temp_nesmr.ibmw.pd = ibfmr->pd;
+ temp_nesmr.ibmw.rkey = ibfmr->rkey;
+ temp_nesmr.ibmw.uobject = NULL;
+
+ return (nes_dealloc_mw(&temp_nesmr.ibmw));
+}
+
+
+/**
+ * nes_map_phys_fmr
+ */
+static int nes_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+ int list_len, u64 iova)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * nes_unmap_frm
+ */
+static int nes_unmap_fmr(struct list_head *ibfmr_list)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * nes_query_device
+ */
+static int nes_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+
+ memset(props, 0, sizeof(*props));
+ memcpy(&props->sys_image_guid, nesvnic->netdev->dev_addr, 6);
+
+ props->fw_ver = nesdev->nesadapter->fw_ver;
+ props->device_cap_flags = nesdev->nesadapter->device_cap_flags;
+ props->vendor_id = nesdev->nesadapter->vendor_id;
+ props->vendor_part_id = nesdev->nesadapter->vendor_part_id;
+ props->hw_ver = nesdev->nesadapter->hw_rev;
+ props->max_mr_size = 0x80000000;
+ props->max_qp = nesibdev->max_qp;
+ props->max_qp_wr = nesdev->nesadapter->max_qp_wr - 2;
+ props->max_sge = nesdev->nesadapter->max_sge;
+ props->max_cq = nesibdev->max_cq;
+ props->max_cqe = nesdev->nesadapter->max_cqe - 1;
+ props->max_mr = nesibdev->max_mr;
+ props->max_mw = nesibdev->max_mr;
+ props->max_pd = nesibdev->max_pd;
+ props->max_sge_rd = 1;
+ switch (nesdev->nesadapter->max_irrq_wr) {
+ case 0:
+ props->max_qp_rd_atom = 1;
+ break;
+ case 1:
+ props->max_qp_rd_atom = 4;
+ break;
+ case 2:
+ props->max_qp_rd_atom = 16;
+ break;
+ case 3:
+ props->max_qp_rd_atom = 32;
+ break;
+ default:
+ props->max_qp_rd_atom = 0;
+ }
+ props->max_qp_init_rd_atom = props->max_qp_wr;
+ props->atomic_cap = IB_ATOMIC_NONE;
+
+ return (0);
+}
+
+
+/**
+ * nes_query_port
+ */
+static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props)
+{
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+
+ memset(props, 0, sizeof(*props));
+
+ props->max_mtu = IB_MTU_2048;
+ props->active_mtu = IB_MTU_2048;
+ props->lid = 1;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = 0;
+ props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP |
+ IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+ props->gid_tbl_len = 1;
+ props->pkey_tbl_len = 1;
+ props->qkey_viol_cntr = 0;
+ props->active_width = IB_WIDTH_4X;
+ props->active_speed = 1;
+ props->max_msg_sz = 0x80000000;
+
+ return (0);
+}
+
+
+/**
+ * nes_modify_port
+ */
+static int nes_modify_port(struct ib_device *ibdev, u8 port,
+ int port_modify_mask, struct ib_port_modify *props)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * nes_query_pkey
+ */
+static int nes_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey)
+{
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+ *pkey = 0;
+ return (0);
+}
+
+
+/**
+ * nes_query_gid
+ */
+static int nes_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+ memcpy(&(gid->raw[0]), nesvnic->netdev->dev_addr, 6);
+
+ return (0);
+}
+
+
+/**
+ * nes_alloc_ucontext - Allocate the user context data structure. This keeps track
+ * of all objects associated with a particular user-mode client.
+ */
+static struct ib_ucontext *nes_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_alloc_ucontext_resp uresp;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ memset(&uresp, 0, sizeof uresp);
+
+ uresp.max_qps = nesibdev->max_qp;
+ uresp.max_pds = nesibdev->max_pd;
+ uresp.wq_size = nesdev->nesadapter->max_qp_wr*2;
+
+ nes_ucontext = kmalloc(sizeof *nes_ucontext, GFP_KERNEL);
+ if (!nes_ucontext)
+ return (ERR_PTR(-ENOMEM));
+
+ memset(nes_ucontext, 0, sizeof(struct nes_ucontext));
+
+ nes_ucontext->nesdev = nesdev;
+ nes_ucontext->mmap_wq_offset = ((uresp.max_pds * 4096) + PAGE_SIZE-1) / PAGE_SIZE;
+ nes_ucontext->mmap_cq_offset = nes_ucontext->mmap_wq_offset +
+ ((sizeof(struct nes_hw_qp_wqe) * uresp.max_qps * 2) + PAGE_SIZE-1) /
+ PAGE_SIZE;
+
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ kfree(nes_ucontext);
+ return (ERR_PTR(-EFAULT));
+ }
+
+ INIT_LIST_HEAD(&nes_ucontext->cq_reg_mem_list);
+ return(&nes_ucontext->ibucontext);
+}
+
+
+/**
+ * nes_dealloc_ucontext
+ */
+static int nes_dealloc_ucontext(struct ib_ucontext *context)
+{
+ /* struct nes_vnic *nesvnic = to_nesvnic(context->device); */
+ /* struct nes_device *nesdev = nesvnic->nesdev; */
+ struct nes_ucontext *nes_ucontext = to_nesucontext(context);
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ kfree(nes_ucontext);
+ return (0);
+}
+
+
+/**
+ * nes_mmap
+ */
+static int nes_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ unsigned long index;
+ struct nes_vnic *nesvnic = to_nesvnic(context->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* struct nes_adapter *nesadapter = nesdev->nesadapter; */
+ struct nes_ucontext *nes_ucontext;
+ struct nes_qp *nesqp;
+
+ nes_ucontext = to_nesucontext(context);
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ if (vma->vm_pgoff >= nes_ucontext->mmap_wq_offset) {
+ index = (vma->vm_pgoff - nes_ucontext->mmap_wq_offset) * PAGE_SIZE;
+ index /= ((sizeof(struct nes_hw_qp_wqe) * nesdev->nesadapter->max_qp_wr * 2) +
+ PAGE_SIZE-1) & (~(PAGE_SIZE-1));
+ if (!test_bit(index, nes_ucontext->allocated_wqs)) {
+ dprintk("%s: wq %lu not allocated\n", __FUNCTION__, index);
+ return (-EFAULT);
+ }
+ nesqp = nes_ucontext->mmap_nesqp[index];
+ if (NULL == nesqp) {
+ dprintk("%s: wq %lu has a NULL QP base.\n", __FUNCTION__, index);
+ return (-EFAULT);
+ }
+ if (remap_pfn_range(vma, vma->vm_start,
+ nesqp->hwqp.sq_pbase >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot)) {
+ dprintk("%s: remap_pfn_range failed.\n", __FUNCTION__);
+ return(-EAGAIN);
+ }
+ vma->vm_private_data = nesqp;
+ return (0);
+ } else {
+ index = vma->vm_pgoff;
+ if (!test_bit(index, nes_ucontext->allocated_doorbells))
+ return(-EFAULT);
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (io_remap_pfn_range(vma, vma->vm_start,
+ (nesdev->doorbell_start +
+ ((nes_ucontext->mmap_db_index[index]-nesdev->base_doorbell_index) * 4096))
+ >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot))
+ return(-EAGAIN);
+ vma->vm_private_data = nes_ucontext;
+ return (0);
+ }
+
+ return(-ENOSYS);
+}
+
+
+/**
+ * nes_alloc_pd
+ */
+static struct ib_pd *nes_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ struct nes_pd *nespd;
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_ucontext *nesucontext;
+ struct nes_alloc_pd_resp uresp;
+ u32 pd_num = 0;
+ int err;
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+ dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_pds,
+ nesadapter->max_pd, &pd_num, &nesadapter->next_pd);
+ if (err) {
+ return (ERR_PTR(err));
+ }
+
+ nespd = kmalloc(sizeof (struct nes_pd), GFP_KERNEL);
+ if (!nespd) {
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ return (ERR_PTR(-ENOMEM));
+ }
+ memset(nespd, 0, sizeof(struct nes_pd));
+ dprintk("Allocating PD (%p) for ib device %s\n",
+ nespd, nesvnic->nesibdev->ibdev.name);
+
+ nespd->pd_id = pd_num + nesadapter->base_pd;
+
+ if (context) {
+ nesucontext = to_nesucontext(context);
+ nespd->mmap_db_index = find_next_zero_bit(nesucontext->allocated_doorbells,
+ NES_MAX_USER_DB_REGIONS, nesucontext->first_free_db);
+ dprintk("find_first_zero_biton doorbells returned %u, mapping pd_id %u.\n",
+ nespd->mmap_db_index, nespd->pd_id);
+ if (nespd->mmap_db_index > NES_MAX_USER_DB_REGIONS) {
+ dprintk("%s:%u: mmap_db_index > MAX\n", __FUNCTION__, __LINE__);
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ kfree(nespd);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ uresp.pd_id = nespd->pd_id;
+ uresp.mmap_db_index = nespd->mmap_db_index;
+ if (ib_copy_to_udata(udata, &uresp, sizeof (struct nes_alloc_pd_resp))) {
+ nes_free_resource(nesadapter, nesadapter->allocated_pds, pd_num);
+ kfree(nespd);
+ return (ERR_PTR(-EFAULT));
+ }
+
+ set_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+ nesucontext->mmap_db_index[nespd->mmap_db_index] = nespd->pd_id;
+ nesucontext->first_free_db = nespd->mmap_db_index + 1;
+ }
+
+ dprintk("%s: PD%u structure located @%p.\n",
+ __FUNCTION__, nespd->pd_id, nespd);
+ dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt));
+ return(&nespd->ibpd);
+}
+
+
+/**
+ * nes_dealloc_pd
+ */
+static int nes_dealloc_pd(struct ib_pd *ibpd)
+{
+ struct nes_ucontext *nesucontext;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+
+ if ((ibpd->uobject) && (ibpd->uobject->context)) {
+ nesucontext = to_nesucontext(ibpd->uobject->context);
+ dprintk("%s: Clearing bit %u from allocated doorbells\n",
+ __FUNCTION__, nespd->mmap_db_index);
+ clear_bit(nespd->mmap_db_index, nesucontext->allocated_doorbells);
+ nesucontext->mmap_db_index[nespd->mmap_db_index] = 0;
+ if (nesucontext->first_free_db > nespd->mmap_db_index) {
+ nesucontext->first_free_db = nespd->mmap_db_index;
+ }
+ }
+
+ dprintk("%s: Deallocating PD%u structure located @%p.\n",
+ __FUNCTION__, nespd->pd_id, nespd);
+ nes_free_resource(nesadapter, nesadapter->allocated_pds,
+ nespd->pd_id-nesadapter->base_pd);
+ kfree(nespd);
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ /* dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt)); */
+ return (0);
+}
+
+
+/**
+ * nes_create_ah
+ */
+static struct ib_ah *nes_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (ERR_PTR(-ENOSYS));
+}
+
+
+/**
+ * nes_destroy_ah
+ */
+static int nes_destroy_ah(struct ib_ah *ah)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (-ENOSYS);
+}
+
+
+/**
+ * nes_create_qp
+ */
+static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
+ struct ib_qp_init_attr *init_attr, struct ib_udata *udata)
+{
+ u64 u64temp= 0;
+ u64 u64nesqp = 0;
+ struct nes_pd *nespd = to_nespd(ibpd);
+ struct nes_vnic *nesvnic = to_nesvnic(ibpd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_qp *nesqp;
+ struct nes_cq *nescq;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ struct nes_create_qp_resp uresp;
+ u32 qp_num = 0;
+ /* u32 counter = 0; */
+ void *mem;
+ unsigned long flags;
+ int ret;
+ int sq_size;
+ int rq_size;
+ u8 sq_encoded_size;
+ u8 rq_encoded_size;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+ u32 mem_size;
+ void *vmem;
+#endif
+ /* int counter; */
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+ dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt));
+
+ atomic_inc(&qps_created);
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC:
+ init_attr->cap.max_inline_data = 0;
+
+ if (init_attr->cap.max_send_wr < 32) {
+ sq_size = 32;
+ sq_encoded_size = 1;
+ } else if (init_attr->cap.max_send_wr < 128) {
+ sq_size = 128;
+ sq_encoded_size = 2;
+ } else if (init_attr->cap.max_send_wr < 512) {
+ sq_size = 512;
+ sq_encoded_size = 3;
+ } else {
+ printk(KERN_ERR PFX "%s: SQ size (%u) too large.\n",
+ __FUNCTION__, init_attr->cap.max_send_wr);
+ return (ERR_PTR(-EINVAL));
+ }
+ init_attr->cap.max_send_wr = sq_size - 2;
+ if (init_attr->cap.max_recv_wr < 32) {
+ rq_size = 32;
+ rq_encoded_size = 1;
+ } else if (init_attr->cap.max_recv_wr < 128) {
+ rq_size = 128;
+ rq_encoded_size = 2;
+ } else if (init_attr->cap.max_recv_wr < 512) {
+ rq_size = 512;
+ rq_encoded_size = 3;
+ } else {
+ printk(KERN_ERR PFX "%s: RQ size (%u) too large.\n",
+ __FUNCTION__, init_attr->cap.max_recv_wr);
+ return (ERR_PTR(-EINVAL));
+ }
+ init_attr->cap.max_recv_wr = rq_size -1;
+ dprintk("%s: RQ size = %u, SQ Size = %u.\n", __FUNCTION__,
+ rq_size, sq_size);
+
+ ret = nes_alloc_resource(nesadapter, nesadapter->allocated_qps,
+ nesadapter->max_qp, &qp_num, &nesadapter->next_qp);
+ if (ret) {
+ return (ERR_PTR(ret));
+ }
+
+ /* Need 512 (actually now 1024) byte alignment on this structure */
+ mem = kzalloc(sizeof(*nesqp)+NES_SW_CONTEXT_ALIGN-1, GFP_KERNEL);
+ if (!mem) {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ dprintk("%s: Unable to allocate QP\n", __FUNCTION__);
+ return (ERR_PTR(-ENOMEM));
+ }
+ u64nesqp = (u64)mem; /* u64nesqp = (u64)((uint)mem); */
+ u64nesqp += ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+ u64temp = ((u64)NES_SW_CONTEXT_ALIGN) - 1;
+ u64nesqp &= ~u64temp;
+ nesqp = (struct nes_qp *)u64nesqp;
+ dprintk("nesqp = %p, allocated buffer = %p. Rounded to closest %u\n",
+ nesqp, mem, NES_SW_CONTEXT_ALIGN);
+ nesqp->allocated_buffer = mem;
+
+ if (udata) {
+ if ((ibpd->uobject) && (ibpd->uobject->context)) {
+ nesqp->user_mode = 1;
+ nes_ucontext = to_nesucontext(ibpd->uobject->context);
+ nesqp->mmap_sq_db_index =
+ find_next_zero_bit(nes_ucontext->allocated_wqs,
+ NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq);
+ dprintk("find_first_zero_biton wqs returned %u\n",
+ nespd->mmap_db_index);
+ if (nesqp->mmap_sq_db_index > NES_MAX_USER_WQ_REGIONS) {
+ dprintk("%s: db index > max user regions, failing create QP\n",
+ __FUNCTION__);
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return (ERR_PTR(-ENOMEM));
+ }
+ set_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+ nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = nesqp;
+ nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index + 1;
+ } else {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return (ERR_PTR(-EFAULT));
+ }
+ }
+
+ nesqp->qp_mem_size = (sizeof(struct nes_hw_qp_wqe) * sq_size) +
+ (sizeof(struct nes_hw_qp_wqe) * rq_size) +
+ max((u32)sizeof(struct nes_qp_context), ((u32)256)) +
+ 256; /* this is Q2 */
+ /* Round up to a multiple of a page */
+ nesqp->qp_mem_size += PAGE_SIZE - 1;
+ nesqp->qp_mem_size &= ~(PAGE_SIZE - 1);
+
+ mem = pci_alloc_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ &nesqp->hwqp.sq_pbase);
+ if (!mem) {
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ dprintk("%s: Unable to allocate memory for host descriptor rings\n",
+ __FUNCTION__);
+ kfree(nesqp->allocated_buffer);
+ return (ERR_PTR(-ENOMEM));
+ }
+ dprintk(PFX "%s: PCI consistent memory for "
+ "host descriptor rings located @ %p (pa = 0x%08lX.) size = %u.\n",
+ __FUNCTION__, mem, (unsigned long)nesqp->hwqp.sq_pbase,
+ nesqp->qp_mem_size);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+ mem_size = nesqp->qp_mem_size;
+ vmem = mem;
+ while (mem_size > 0) {
+ dprintk("%s: Setting memory page %p reserved, mem_size=%u\n",
+ __FUNCTION__, vmem, mem_size);
+ SetPageReserved(virt_to_page(vmem));
+ mem_size -= PAGE_SIZE;
+ vmem += PAGE_SIZE;
+ }
+#endif
+
+ memset(mem, 0, nesqp->qp_mem_size);
+
+ nesqp->hwqp.sq_vbase = mem;
+ nesqp->hwqp.sq_size = sq_size;
+ nesqp->hwqp.sq_encoded_size = sq_encoded_size;
+ nesqp->hwqp.sq_head = 1;
+ mem += sizeof(struct nes_hw_qp_wqe) * sq_size;
+
+ nesqp->hwqp.rq_vbase = mem;
+ nesqp->hwqp.rq_size = rq_size;
+ nesqp->hwqp.rq_encoded_size = rq_encoded_size;
+ nesqp->hwqp.rq_pbase = nesqp->hwqp.sq_pbase +
+ sizeof(struct nes_hw_qp_wqe) * sq_size;
+ mem += sizeof(struct nes_hw_qp_wqe)*rq_size;
+
+ nesqp->hwqp.q2_vbase = mem;
+ nesqp->hwqp.q2_pbase = nesqp->hwqp.rq_pbase +
+ sizeof(struct nes_hw_qp_wqe) * rq_size;
+ mem += 256;
+ memset(nesqp->hwqp.q2_vbase, 0, 256);
+
+ nesqp->nesqp_context = mem;
+ nesqp->nesqp_context_pbase = nesqp->hwqp.q2_pbase + 256;
+ memset(nesqp->nesqp_context, 0, sizeof(*nesqp->nesqp_context));
+
+ dprintk("%s:%u: nesqp->nesqp_context_pbase = %p\n",
+ __FUNCTION__, __LINE__, (void *) nesqp->nesqp_context_pbase);
+
+ nesqp->hwqp.qp_id = qp_num;
+ nesqp->ibqp.qp_num = nesqp->hwqp.qp_id;
+ nesqp->nespd = nespd;
+
+ nescq = to_nescq(init_attr->send_cq);
+ nesqp->nesscq = nescq;
+ nescq = to_nescq(init_attr->recv_cq);
+ nesqp->nesrcq = nescq;
+
+ nesqp->nesqp_context->misc |= (u32)PCI_FUNC(nesdev->pcidev->devfn) <<
+ NES_QPCONTEXT_MISC_PCI_FCN_SHIFT;
+ nesqp->nesqp_context->misc |= (u32)nesqp->hwqp.rq_encoded_size <<
+ NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT;
+ nesqp->nesqp_context->misc |= (u32)nesqp->hwqp.sq_encoded_size <<
+ NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT;
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_PRIV_EN;
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_FAST_REGISTER_EN;
+ nesqp->nesqp_context->cqs = nesqp->nesscq->hw_cq.cq_number +
+ ((u32)nesqp->nesrcq->hw_cq.cq_number << 16);
+ u64temp = (u64)nesqp->hwqp.sq_pbase;
+ nesqp->nesqp_context->sq_addr_low = (u32)u64temp;
+ nesqp->nesqp_context->sq_addr_high = (u32)(u64temp >> 32);
+ u64temp = (u64)nesqp->hwqp.rq_pbase;
+ nesqp->nesqp_context->rq_addr_low = (u32)u64temp;
+ nesqp->nesqp_context->rq_addr_high = (u32)(u64temp >> 32);
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ dprintk("%s: next_qp_nic_index=%u, using nic_index=%d\n",
+ __FUNCTION__, nesvnic->next_qp_nic_index,
+ nesvnic->qp_nic_index[nesvnic->next_qp_nic_index]);
+ nesqp->nesqp_context->misc2 |=
+ (u32)nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] <<
+ NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT;
+ nesvnic->next_qp_nic_index++;
+ if ((nesvnic->next_qp_nic_index > 3) ||
+ (nesvnic->qp_nic_index[nesvnic->next_qp_nic_index] == 0xf)) {
+ nesvnic->next_qp_nic_index = 0;
+ }
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ nesqp->nesqp_context->pd_index_wscale |= (u32)nesqp->nespd->pd_id << 16;
+ u64temp = (u64)nesqp->hwqp.q2_pbase;
+ nesqp->nesqp_context->q2_addr_low = (u32)u64temp;
+ nesqp->nesqp_context->q2_addr_high = (u32)(u64temp>>32);
+ *((struct nes_qp **)&nesqp->nesqp_context->aeq_token_low) = nesqp;
+ nesqp->nesqp_context->ird_ord_sizes = NES_QPCONTEXT_ORDIRD_ALSMM |
+ ((((u32)nesadapter->max_irrq_wr) <<
+ NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT) & NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK);
+ if (disable_mpa_crc) {
+ dprintk("%s Disabling MPA crc checking due to module option.\n", __FUNCTION__);
+ nesqp->nesqp_context->ird_ord_sizes |= NES_QPCONTEXT_ORDIRD_RNMC;
+ }
+
+
+ /* Create the QP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+ kfree(nesqp->allocated_buffer);
+ return (ERR_PTR(-ENOMEM));
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_IWARP |
+ NES_CQP_QP_IWARP_STATE_IDLE;
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_QP_CQS_VALID;
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = nesqp->hwqp.qp_id;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nesqp->nesqp_context_pbase;
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_LOW_IDX] = (u32)u64temp;
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_HIGH_IDX] = (u32)(u64temp >> 32);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ /* dprintk("Waiting for create iWARP QP%u to complete.\n",
+ nesqp->hwqp.qp_id); */
+ ret = wait_event_timeout(cqp_request->waitq,
+ (0 != cqp_request->request_done), NES_EVENT_TIMEOUT);
+ dprintk("Create iwarp QP completed, wait_event_timeout ret=%u,"
+ " nesdev->cqp_head = %u, nesdev->cqp.sq_tail = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ ret, nesdev->cqp.sq_head, nesdev->cqp.sq_tail,
+ cqp_request->major_code, cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+ kfree(nesqp->allocated_buffer);
+ if (!ret) {
+ return (ERR_PTR(-ETIME));
+ } else {
+ return (ERR_PTR(-EIO));
+ }
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ if (ibpd->uobject) {
+ uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+ uresp.actual_sq_size = sq_size;
+ uresp.actual_rq_size = rq_size;
+ uresp.qp_id = nesqp->hwqp.qp_id;
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ pci_free_consistent(nesdev->pcidev, nesqp->qp_mem_size,
+ nesqp->hwqp.sq_vbase, nesqp->hwqp.sq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num);
+ kfree(nesqp->allocated_buffer);
+ return (ERR_PTR(-EFAULT));
+ }
+ }
+
+ dprintk("%s: QP%u structure located @%p.Size = %u.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, nesqp, (u32)sizeof(*nesqp));
+ spin_lock_init(&nesqp->lock);
+ init_waitqueue_head(&nesqp->state_waitq);
+ init_waitqueue_head(&nesqp->kick_waitq);
+ nes_add_ref(&nesqp->ibqp);
+ break;
+ default:
+ dprintk("%s: Invalid QP type: %d\n", __FUNCTION__, init_attr->qp_type);
+ return (ERR_PTR(-EINVAL));
+ break;
+ }
+
+ /* update the QP table */
+ nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
+ dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt));
+
+ return (&nesqp->ibqp);
+}
+
+
+/**
+ * nes_destroy_qp
+ */
+static int nes_destroy_qp(struct ib_qp *ibqp)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ /* struct nes_vnic *nesvnic = to_nesvnic(ibqp->device); */
+ struct nes_ucontext *nes_ucontext;
+ struct ib_qp_attr attr;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+ u32 mem_size;
+ void *vmem;
+#endif
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ int ret;
+
+ dprintk("%s:%u: Destroying QP%u, qp reference count = %d\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+ atomic_inc(&sw_qps_destroyed);
+ /* Blow away the connection if it exists. */
+ if (((nesqp->ibqp_state == IB_QPS_INIT) ||
+ (nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
+ cm_id = nesqp->cm_id;
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ dprintk("%s: Generating a CM Timeout Event for "
+ " QP%u. cm_id = %p, refcount = %u. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id,
+ cm_id, atomic_read(&nesqp->refcount));
+
+ cm_id->rem_ref(cm_id);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ }
+
+ if (nesqp->ibqp_state == IB_QPS_RTS) {
+ attr.qp_state = IB_QPS_ERR;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+ }
+
+ if (nesqp->user_mode) {
+ if ((ibqp->uobject)&&(ibqp->uobject->context)) {
+ nes_ucontext = to_nesucontext(ibqp->uobject->context);
+ clear_bit(nesqp->mmap_sq_db_index, nes_ucontext->allocated_wqs);
+ nes_ucontext->mmap_nesqp[nesqp->mmap_sq_db_index] = NULL;
+ if (nes_ucontext->first_free_wq > nesqp->mmap_sq_db_index) {
+ nes_ucontext->first_free_wq = nesqp->mmap_sq_db_index;
+ }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10))
+ mem_size = nesqp->qp_mem_size;
+ vmem = nesqp->hwqp.sq_vbase;
+ while (mem_size > 0) {
+ dprintk("%s: Remove reserved memory page %p, mem_size=%u\n",
+ __FUNCTION__, vmem, mem_size);
+ ClearPageReserved(virt_to_page(vmem));
+ mem_size -= PAGE_SIZE;
+ vmem += PAGE_SIZE;
+ }
+#endif
+ }
+ }
+
+ nes_rem_ref(&nesqp->ibqp);
+ /* dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt)); */
+ dprintk("%s:%u: QP%u, leaving\n", __FUNCTION__, __LINE__, nesqp->hwqp.qp_id);
+ return (0);
+}
+
+
+/**
+ * nes_create_cq
+ */
+static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = to_nesvnic(ibdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_cq *nescq;
+ struct nes_ucontext *nes_ucontext = NULL;
+ struct nes_cqp_request *cqp_request;
+ void *mem = NULL;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_pbl *nespbl = NULL;
+ struct nes_create_cq_req req;
+ struct nes_create_cq_resp resp;
+ u32 cq_num = 0;
+ u32 pbl_entries = 1;
+ int err;
+ unsigned long flags;
+ int ret;
+
+ dprintk("%s:%u: entries = %u\n", __FUNCTION__, __LINE__, entries);
+ /* dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt)); */
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_cqs,
+ nesadapter->max_cq, &cq_num, &nesadapter->next_cq);
+ if (err) {
+ return (ERR_PTR(err));
+ }
+
+ nescq = kmalloc(sizeof(struct nes_cq), GFP_KERNEL);
+ if (!nescq) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ dprintk("%s: Unable to allocate CQ\n", __FUNCTION__);
+ return (ERR_PTR(-ENOMEM));
+ }
+ memset(nescq, 0, sizeof (struct nes_cq));
+
+ nescq->hw_cq.cq_size = max(entries + 1, 5);
+ nescq->hw_cq.cq_number = cq_num;
+ nescq->ibcq.cqe = nescq->hw_cq.cq_size - 1;
+
+ if (context) {
+ nes_ucontext = to_nesucontext(context);
+ if (ib_copy_from_udata(&req, udata, sizeof (struct nes_create_cq_req))) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-EFAULT));
+ }
+ dprintk("%s: CQ Virtual Address = %08lX, size = %u.\n",
+ __FUNCTION__, (unsigned long)req.user_cq_buffer, entries);
+ list_for_each_entry(nespbl, &nes_ucontext->cq_reg_mem_list, list) {
+ if (nespbl->user_base == (unsigned long )req.user_cq_buffer) {
+ list_del(&nespbl->list);
+ err = 0;
+ dprintk("%s: Found PBL for virtual CQ. nespbl=%p.\n",
+ __FUNCTION__, nespbl);
+ break;
+ }
+ }
+ if (err) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(err));
+ }
+ pbl_entries = nespbl->pbl_size >> 3;
+ nescq->cq_mem_size = 0;
+ dprintk("%s: Userspace PBL, pbl_size=%u, pbl_vbase=%p, pbl_pbase=%p\n",
+ __FUNCTION__, nespbl->pbl_size, (void *)nespbl->pbl_vbase,
+ (void *)nespbl->pbl_pbase);
+ dprintk("%s: pbl_entries=%u, cq_mem_size=%u\n",
+ __FUNCTION__, pbl_entries, nescq->cq_mem_size);
+ } else {
+ nescq->cq_mem_size = nescq->hw_cq.cq_size * sizeof(struct nes_hw_cqe);
+ dprintk("%s: Attempting to allocate pci memory (%u entries, %u bytes) for CQ%u.\n",
+ __FUNCTION__, entries, nescq->cq_mem_size, nescq->hw_cq.cq_number);
+
+ /* allocate the physical buffer space */
+ mem = pci_alloc_consistent(nesdev->pcidev, nescq->cq_mem_size,
+ &nescq->hw_cq.cq_pbase);
+ if (!mem) {
+ dprintk(KERN_ERR PFX "Unable to allocate pci memory for cq\n");
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ memset(mem, 0, nescq->cq_mem_size);
+ nescq->hw_cq.cq_vbase = mem;
+ nescq->hw_cq.cq_head = 0;
+ dprintk("%s: CQ%u virtual address @ %p, phys = 0x%08X\n",
+ __FUNCTION__, nescq->hw_cq.cq_number, nescq->hw_cq.cq_vbase,
+ (u32)nescq->hw_cq.cq_pbase);
+ }
+
+ nescq->hw_cq.ce_handler = nes_iwarp_ce_handler;
+ spin_lock_init(&nescq->lock);
+
+ /* send CreateCQ request to CQP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-ENOMEM));
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+ NES_CQP_CQ_CHK_OVERFLOW |
+ NES_CQP_CQ_CEQE_MASK |((u32)nescq->hw_cq.cq_size << 16);
+ if (1 != pbl_entries) {
+ if (pbl_entries > 32) {
+ /* use 4k pbl */
+ dprintk("%s: pbl_entries=%u, use a 4k PBL\n", __FUNCTION__, pbl_entries);
+ if (0 == nesadapter->free_4kpbl) {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-ENOMEM));
+ } else {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ (NES_CQP_CQ_VIRT | NES_CQP_CQ_4KB_CHUNK);
+ nescq->virtual_cq = 2;
+ nesadapter->free_4kpbl--;
+ }
+ } else {
+ /* use 256 byte pbl */
+ dprintk("%s: pbl_entries=%u, use a 256 byte PBL\n",
+ __FUNCTION__, pbl_entries);
+ if (0 == nesadapter->free_256pbl) {
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-ENOMEM));
+ } else {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_CQ_VIRT;
+ nescq->virtual_cq = 1;
+ nesadapter->free_256pbl--;
+ }
+ }
+ }
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
+ cpu_to_le32(nescq->hw_cq.cq_number | ((u32)nesdev->ceq_index << 16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ if (context) {
+ if (1 != pbl_entries)
+ u64temp = (u64)nespbl->pbl_pbase;
+ else
+ u64temp = nespbl->pbl_vbase[0];
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] =
+ cpu_to_le32(nes_ucontext->mmap_db_index[0]);
+ } else {
+ u64temp = (u64)nescq->hw_cq.cq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+ }
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ *((struct nes_hw_cq **)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) =
+ &nescq->hw_cq;
+ *((u64 *)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) >>= 1;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("Waiting for create iWARP CQ%u to complete.\n", nescq->hw_cq.cq_number);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT * 2);
+ dprintk("Create iWARP CQ%u completed, wait_event_timeout ret = %d.\n",
+ nescq->hw_cq.cq_number, ret);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ dprintk("iWARP CQ%u create timeout expired, major code = 0x%04X,"
+ " minor code = 0x%04X\n",
+ nescq->hw_cq.cq_number, cqp_request->major_code, cqp_request->minor_code);
+ if (!context)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size, mem,
+ nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-EIO));
+ } else {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ if (context) {
+ /* free the nespbl */
+ pci_free_consistent(nesdev->pcidev, nespbl->pbl_size, nespbl->pbl_vbase,
+ nespbl->pbl_pbase);
+ kfree(nespbl);
+ resp.cq_id = nescq->hw_cq.cq_number;
+ resp.cq_size = nescq->hw_cq.cq_size;
+ resp.mmap_db_index = 0;
+ if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
+ kfree(nescq);
+ return (ERR_PTR(-EFAULT));
+ }
+ }
+
+ dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt));
+ return(&nescq->ibcq);
+}
+
+
+/**
+ * nes_destroy_cq
+ */
+static int nes_destroy_cq(struct ib_cq *ib_cq)
+{
+ struct nes_cq *nescq;
+ struct nes_device *nesdev;
+ struct nes_vnic *nesvnic;
+ struct nes_adapter *nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+
+ dprintk("%s:%u: %p.\n", __FUNCTION__, __LINE__, ib_cq);
+
+ if (ib_cq == NULL)
+ return (0);
+
+ nescq = to_nescq(ib_cq);
+ nesvnic = to_nesvnic(ib_cq->device);
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+ /* dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt)); */
+
+ dprintk("%s:%u: Destroy CQ%u\n",
+ __FUNCTION__, __LINE__, nescq->hw_cq.cq_number);
+
+ /* Send DestroyCQ request to CQP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_DESTROY_CQ | (nescq->hw_cq.cq_size << 16);
+
+ if (nescq->virtual_cq == 1) {
+ nesadapter->free_256pbl++;
+ if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+ printk(KERN_ERR PFX "%s: free 256B PBLs(%u) has exceeded the max(%u)\n",
+ __FUNCTION__, nesadapter->free_256pbl, nesadapter->max_256pbl);
+ }
+ } else if (nescq->virtual_cq == 2) {
+ nesadapter->free_4kpbl++;
+ if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+ printk(KERN_ERR PFX "%s: free 4K PBLs(%u) has exceeded the max(%u)\n",
+ __FUNCTION__, nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+ }
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_CQ_4KB_CHUNK;
+ }
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
+ nescq->hw_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 16);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("Waiting for destroy iWARP CQ%u to complete.\n",
+ nescq->hw_cq.cq_number);
+ /* cqp_head = (cqp_head+1)&(nesdev->cqp.sq_size-1); */
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("Destroy iWARP CQ%u completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ nescq->hw_cq.cq_number, ret, cqp_request->major_code,
+ cqp_request->minor_code);
+ if ((!ret) || (cqp_request->major_code)) {
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret) {
+ dprintk("iWARP CQ%u destroy timeout expired\n", nescq->hw_cq.cq_number);
+ ret = -ETIME;
+ } else {
+ dprintk("iWARP CQ%u destroy failed\n", nescq->hw_cq.cq_number);
+ ret = -EIO;
+ }
+ } else {
+ ret = 0;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+
+ if (nescq->cq_mem_size)
+ pci_free_consistent(nesdev->pcidev, nescq->cq_mem_size,
+ (void *)nescq->hw_cq.cq_vbase, nescq->hw_cq.cq_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_cqs, nescq->hw_cq.cq_number);
+ kfree(nescq);
+
+ /* dprintk("%s: netdev refcnt = %u.\n", __FUNCTION__,
+ atomic_read(&nesvnic->netdev->refcnt)); */
+ return (ret);
+}
+
+
+/**
+ * nes_reg_mr
+ */
+static int nes_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd,
+ u32 stag, u64 region_length, struct nes_root_vpbl *root_vpbl,
+ dma_addr_t single_buffer, u16 pbl_count, u16 residual_page_count,
+ int acc, u64 *iova_start)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ /* int count; */
+ u16 major_code;
+
+ /* Register the region with the adapter */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ /* track PBL resources */
+ if (pbl_count != 0) {
+ if (pbl_count > 1) {
+ /* Two level PBL */
+ if ((pbl_count+1) > nesadapter->free_4kpbl) {
+ dprintk("%s: Out of 4KB Pbls for two level request.\n",
+ __FUNCTION__);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return(-ENOMEM);
+ } else {
+ nesadapter->free_4kpbl -= pbl_count+1;
+ }
+ } else if (residual_page_count > 32) {
+ if (pbl_count > nesadapter->free_4kpbl) {
+ dprintk("%s: Out of 4KB Pbls.\n", __FUNCTION__);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ } else {
+ nesadapter->free_4kpbl -= pbl_count;
+ }
+ } else {
+ if (pbl_count > nesadapter->free_256pbl) {
+ dprintk("%s: Out of 256B Pbls.\n", __FUNCTION__);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ } else {
+ nesadapter->free_256pbl -= pbl_count;
+ }
+ }
+ }
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_REGISTER_STAG | NES_CQP_STAG_RIGHTS_LOCAL_READ;
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ NES_CQP_STAG_VA_TO | NES_CQP_STAG_MR;
+ if (acc & IB_ACCESS_LOCAL_WRITE) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_STAG_RIGHTS_LOCAL_WRITE;
+ }
+ if (acc & IB_ACCESS_REMOTE_WRITE) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE | NES_CQP_STAG_REM_ACC_EN;
+ }
+ if (acc & IB_ACCESS_REMOTE_READ) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ NES_CQP_STAG_RIGHTS_REMOTE_READ | NES_CQP_STAG_REM_ACC_EN;
+ }
+ if (acc & IB_ACCESS_MW_BIND) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ NES_CQP_STAG_RIGHTS_WINDOW_BIND | NES_CQP_STAG_REM_ACC_EN;
+ }
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_VA_LOW_IDX] = cpu_to_le32((u32)*iova_start);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_VA_HIGH_IDX] =
+ cpu_to_le32((u32)((((u64)*iova_start) >> 32)));
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_LOW_IDX] = cpu_to_le32((u32)region_length);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] =
+ cpu_to_le32((u32)(region_length >> 8) & 0xff000000);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX] |=
+ cpu_to_le32(nespd->pd_id & 0x00007fff);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_STAG_IDX] = cpu_to_le32(stag);
+
+ if (pbl_count == 0) {
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] =
+ cpu_to_le32((u32)single_buffer);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] =
+ cpu_to_le32((u32)((((u64)single_buffer) >> 32)));
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+ } else {
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_LOW_IDX] =
+ cpu_to_le32((u32)root_vpbl->pbl_pbase);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PA_HIGH_IDX] =
+ cpu_to_le32((u32)((((u64)root_vpbl->pbl_pbase) >> 32)));
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = cpu_to_le32(pbl_count);
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] =
+ cpu_to_le32(((pbl_count-1) * 4096) + (residual_page_count*8));
+ if ((pbl_count > 1) || (residual_page_count > 32)) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_STAG_PBL_BLK_SIZE;
+ }
+ }
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+
+ barrier();
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s: Register STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ __FUNCTION__, stag, ret, cqp_request->major_code, cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret)
+ return(-ETIME);
+ else if (major_code)
+ return(-EIO);
+ else
+ return (0);
+
+ return (0);
+}
+
+
+/**
+ * nes_reg_phys_mr
+ */
+static struct ib_mr *nes_reg_phys_mr(struct ib_pd *ib_pd,
+ struct ib_phys_buf *buffer_list, int num_phys_buf, int acc,
+ u64 * iova_start)
+{
+ u64 region_length;
+ struct nes_pd *nespd = to_nespd(ib_pd);
+ struct nes_vnic *nesvnic = to_nesvnic(ib_pd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_mr *nesmr;
+ struct ib_mr *ibmr;
+ struct nes_vpbl vpbl;
+ struct nes_root_vpbl root_vpbl;
+ u32 stag;
+ u32 i;
+ u32 stag_index = 0;
+ u32 next_stag_index = 0;
+ u32 driver_key = 0;
+ u32 root_pbl_index = 0;
+ u32 cur_pbl_index = 0;
+ int err = 0, pbl_depth = 0;
+ int ret = 0;
+ u16 pbl_count = 0;
+ u8 single_page = 1;
+ u8 stag_key = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ pbl_depth = 0;
+ region_length = 0;
+ vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_pbase = 0;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+ if (num_phys_buf > (1024*512)) {
+ return (ERR_PTR(-E2BIG));
+ }
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs, nesadapter->max_mr,
+ &stag_index, &next_stag_index);
+ if (err) {
+ return (ERR_PTR(err));
+ }
+
+ nesmr = kmalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ for (i = 0; i < num_phys_buf; i++) {
+
+ if ((i & 0x01FF) == 0) {
+ if (1 == root_pbl_index) {
+ /* Allocate the root PBL */
+ root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 8192,
+ &root_vpbl.pbl_pbase);
+ dprintk("%s: Allocating root PBL, va = %p, pa = 0x%08X\n",
+ __FUNCTION__, root_vpbl.pbl_vbase,
+ (unsigned int)root_vpbl.pbl_pbase);
+ if (!root_vpbl.pbl_vbase) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ return (ERR_PTR(-ENOMEM));
+ }
+ root_vpbl.leaf_vpbl = kmalloc(sizeof(*root_vpbl.leaf_vpbl)*1024, GFP_KERNEL);
+ if (!root_vpbl.leaf_vpbl) {
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ return (ERR_PTR(-ENOMEM));
+ }
+ root_vpbl.pbl_vbase[0].pa_low = cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[0].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[0] = vpbl;
+ }
+ /* Allocate a 4K buffer for the PBL */
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+ dprintk("%s: Allocating leaf PBL, va = %p, pa = 0x%016lX\n",
+ __FUNCTION__, vpbl.pbl_vbase, (unsigned long)vpbl.pbl_pbase);
+ if (!vpbl.pbl_vbase) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ ibmr = ERR_PTR(-ENOMEM);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+ /* Fill in the root table */
+ if (1 <= root_pbl_index) {
+ root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+ }
+ root_pbl_index++;
+ cur_pbl_index = 0;
+ }
+ if (buffer_list[i].addr & ~PAGE_MASK) {
+ /* TODO: Unwind allocated buffers */
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ dprintk("Unaligned Memory Buffer: 0x%x\n",
+ (unsigned int) buffer_list[i].addr);
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+
+ if (!buffer_list[i].size) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ dprintk("Invalid Buffer Size\n");
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_phys_err;
+ }
+
+ region_length += buffer_list[i].size;
+ if ((i != 0) && (single_page)) {
+ if ((buffer_list[i-1].addr+PAGE_SIZE) != buffer_list[i].addr)
+ single_page = 0;
+ }
+ vpbl.pbl_vbase[cur_pbl_index].pa_low = cpu_to_le32((u32)buffer_list[i].addr);
+ vpbl.pbl_vbase[cur_pbl_index++].pa_high =
+ cpu_to_le32((u32)((((u64)buffer_list[i].addr) >> 32)));
+ }
+
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+
+ dprintk("%s: Registering STag 0x%08X, VA = 0x%016lX,"
+ " length = 0x%016lX, index = 0x%08X\n",
+ __FUNCTION__, stag, (unsigned long)*iova_start,
+ (unsigned long)region_length, stag_index);
+
+ region_length -= (*iova_start)&PAGE_MASK;
+
+ /* Make the leaf PBL the root if only one PBL */
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+ }
+
+ if (single_page) {
+ pbl_count = 0;
+ } else {
+ pbl_count = root_pbl_index;
+ }
+ ret = nes_reg_mr(nesdev, nespd, stag, region_length, &root_vpbl,
+ buffer_list[0].addr, pbl_count, (u16)cur_pbl_index, acc, iova_start);
+
+ if (ret == 0) {
+ nesmr->ibmr.rkey = stag;
+ nesmr->ibmr.lkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+ ibmr = &nesmr->ibmr;
+ nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+ nesmr->pbls_used = pbl_count;
+ if (pbl_count > 1) {
+ nesmr->pbls_used++;
+ }
+ } else {
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ }
+
+ reg_phys_err:
+ /* free the resources */
+ if (root_pbl_index == 1) {
+ /* single PBL case */
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase, vpbl.pbl_pbase);
+ } else {
+ for (i=0; i<root_pbl_index; i++) {
+ pci_free_consistent(nesdev->pcidev, 4096, root_vpbl.leaf_vpbl[i].pbl_vbase,
+ root_vpbl.leaf_vpbl[i].pbl_pbase);
+ }
+ kfree(root_vpbl.leaf_vpbl);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ }
+
+ return (ibmr);
+}
+
+
+/**
+ * nes_get_dma_mr
+ */
+static struct ib_mr *nes_get_dma_mr(struct ib_pd *pd, int acc) {
+ struct ib_phys_buf bl;
+ u64 kva = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ bl.size = (u64)0xffffffffffULL;
+ bl.addr = 0;
+ return (nes_reg_phys_mr(pd, &bl, 1, acc, &kva));
+}
+
+
+/**
+ * nes_reg_user_mr
+ */
+static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+ int acc, struct ib_udata *udata)
+{
+ u64 iova_start;
+ u64 *pbl;
+ u64 region_length;
+ dma_addr_t last_dma_addr = 0;
+ dma_addr_t first_dma_addr = 0;
+ struct nes_pd *nespd = to_nespd(pd);
+ struct nes_vnic *nesvnic = to_nesvnic(pd->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct ib_mr *ibmr;
+ struct ib_umem_chunk *chunk;
+ struct nes_ucontext *nes_ucontext;
+ struct nes_pbl *nespbl;
+ struct nes_mr *nesmr;
+ struct nes_mem_reg_req req;
+ struct nes_vpbl vpbl;
+ struct nes_root_vpbl root_vpbl;
+ int j;
+ int page_count = 0;
+ int err, pbl_depth = 0;
+ int ret;
+ u32 stag;
+ u32 stag_index = 0;
+ u32 next_stag_index;
+ u32 driver_key;
+ u32 root_pbl_index = 0;
+ u32 cur_pbl_index = 0;
+ u16 pbl_count;
+ u8 single_page = 1;
+ u8 stag_key;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ dprintk("%s: User base = 0x%lX, Virt base = 0x%lX, length = %u,"
+ " offset = %u, page size = %u.\n",
+ __FUNCTION__, region->user_base, region->virt_base, (u32)region->length,
+ region->offset, region->page_size);
+
+ if (ib_copy_from_udata(&req, udata, sizeof(req)))
+ return (ERR_PTR(-EFAULT));
+ dprintk("%s: Memory Registration type = %08X.\n", __FUNCTION__, req.reg_type);
+
+ switch (req.reg_type) {
+ case IWNES_MEMREG_TYPE_MEM:
+ pbl_depth = 0;
+ region_length = 0;
+ vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_vbase = NULL;
+ root_vpbl.pbl_pbase = 0;
+
+ get_random_bytes(&next_stag_index, sizeof(next_stag_index));
+ stag_key = (u8)next_stag_index;
+
+ driver_key = 0;
+
+ next_stag_index >>= 8;
+ next_stag_index %= nesadapter->max_mr;
+
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_mrs,
+ nesadapter->max_mr, &stag_index, &next_stag_index);
+ if (err) {
+ return (ERR_PTR(err));
+ }
+
+ nesmr = kmalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ list_for_each_entry(chunk, ®ion->chunk_list, list) {
+ dprintk("%s: Chunk: nents = %u, nmap = %u .\n",
+ __FUNCTION__, chunk->nents, chunk->nmap);
+ for (j = 0; j < chunk->nmap; ++j) {
+ if ((page_count&0x01FF) == 0) {
+ if (page_count>(1024*512)) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter,
+ nesadapter->allocated_mrs, stag_index);
+ kfree(nesmr);
+ return (ERR_PTR(-E2BIG));
+ }
+ if (1 == root_pbl_index) {
+ root_vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev,
+ 8192, &root_vpbl.pbl_pbase);
+ dprintk("%s: Allocating root PBL, va = %p, pa = 0x%08X\n",
+ __FUNCTION__, root_vpbl.pbl_vbase,
+ (unsigned int)root_vpbl.pbl_pbase);
+ if (!root_vpbl.pbl_vbase) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ kfree(nesmr);
+ return (ERR_PTR(-ENOMEM));
+ }
+ root_vpbl.leaf_vpbl = kmalloc(sizeof(*root_vpbl.leaf_vpbl)*1024,
+ GFP_KERNEL);
+ if (!root_vpbl.leaf_vpbl) {
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ kfree(nesmr);
+ return (ERR_PTR(-ENOMEM));
+ }
+ root_vpbl.pbl_vbase[0].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[0].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase) >> 32)));
+ root_vpbl.leaf_vpbl[0] = vpbl;
+ }
+ vpbl.pbl_vbase = pci_alloc_consistent(nesdev->pcidev, 4096,
+ &vpbl.pbl_pbase);
+ dprintk("%s: Allocating leaf PBL, va = %p, pa = 0x%08X\n",
+ __FUNCTION__, vpbl.pbl_vbase, (unsigned int)vpbl.pbl_pbase);
+ if (!vpbl.pbl_vbase) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ ibmr = ERR_PTR(-ENOMEM);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+ if (1 <= root_pbl_index) {
+ root_vpbl.pbl_vbase[root_pbl_index].pa_low =
+ cpu_to_le32((u32)vpbl.pbl_pbase);
+ root_vpbl.pbl_vbase[root_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)vpbl.pbl_pbase)>>32)));
+ root_vpbl.leaf_vpbl[root_pbl_index] = vpbl;
+ }
+ root_pbl_index++;
+ cur_pbl_index = 0;
+ }
+ if (sg_dma_address(&chunk->page_list[j]) & ~PAGE_MASK) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs, stag_index);
+ dprintk("%s: Unaligned Memory Buffer: 0x%x\n", __FUNCTION__,
+ (unsigned int) sg_dma_address(&chunk->page_list[j]));
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+
+ if (!sg_dma_len(&chunk->page_list[j])) {
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ stag_index);
+ dprintk("%s: Invalid Buffer Size\n", __FUNCTION__);
+ ibmr = ERR_PTR(-EINVAL);
+ kfree(nesmr);
+ goto reg_user_mr_err;
+ }
+
+ region_length += sg_dma_len(&chunk->page_list[j]);
+ if (single_page) {
+ if (page_count != 0) {
+ if ((last_dma_addr+PAGE_SIZE) !=
+ sg_dma_address(&chunk->page_list[j]))
+ single_page = 0;
+ last_dma_addr = sg_dma_address(&chunk->page_list[j]);
+ } else {
+ first_dma_addr = sg_dma_address(&chunk->page_list[j]);
+ last_dma_addr = first_dma_addr;
+ }
+ }
+
+ vpbl.pbl_vbase[cur_pbl_index].pa_low =
+ cpu_to_le32((u32)sg_dma_address(&chunk->page_list[j]));
+ vpbl.pbl_vbase[cur_pbl_index].pa_high =
+ cpu_to_le32((u32)((((u64)sg_dma_address(&chunk->page_list[j]))>>32)));
+ cur_pbl_index++;
+ page_count++;
+ }
+ }
+
+ dprintk("%s[%u] calculating stag, stag_index=0x%08x, driver_key=0x%08x,"
+ " stag_key=0x%08x\n", __FUNCTION__, __LINE__,
+ stag_index, driver_key, stag_key);
+ stag = stag_index << 8;
+ stag |= driver_key;
+ stag += (u32)stag_key;
+ if (stag == 0) {
+ stag = 1;
+ }
+
+ iova_start = (u64)region->virt_base;
+ dprintk("%s: Registering STag 0x%08X, VA = 0x%08X, length = 0x%08X,"
+ " index = 0x%08X, region->length=0x%08llx\n",
+ __FUNCTION__, stag, (unsigned int)iova_start,
+ (unsigned int)region_length, stag_index,
+ (unsigned long long)region->length);
+
+ /* Make the leaf PBL the root if only one PBL */
+ if (root_pbl_index == 1) {
+ root_vpbl.pbl_pbase = vpbl.pbl_pbase;
+ }
+
+ if (single_page) {
+ pbl_count = 0;
+ } else {
+ pbl_count = root_pbl_index;
+ first_dma_addr = 0;
+ }
+ ret = nes_reg_mr( nesdev, nespd, stag, region->length, &root_vpbl,
+ first_dma_addr, pbl_count, (u16)cur_pbl_index, acc, &iova_start);
+
+ if (ret == 0) {
+ nesmr->ibmr.rkey = stag;
+ nesmr->ibmr.lkey = stag;
+ nesmr->mode = IWNES_MEMREG_TYPE_MEM;
+ ibmr = &nesmr->ibmr;
+ nesmr->pbl_4k = ((pbl_count > 1) || (cur_pbl_index > 32)) ? 1 : 0;
+ nesmr->pbls_used = pbl_count;
+ if (pbl_count > 1) {
+ nesmr->pbls_used++;
+ }
+ } else {
+ kfree(nesmr);
+ ibmr = ERR_PTR(-ENOMEM);
+ }
+
+ reg_user_mr_err:
+ /* free the resources */
+ if (root_pbl_index == 1) {
+ pci_free_consistent(nesdev->pcidev, 4096, vpbl.pbl_vbase,
+ vpbl.pbl_pbase);
+ } else {
+ for (j=0; j<root_pbl_index; j++) {
+ pci_free_consistent(nesdev->pcidev, 4096,
+ root_vpbl.leaf_vpbl[j].pbl_vbase,
+ root_vpbl.leaf_vpbl[j].pbl_pbase);
+ }
+ kfree(root_vpbl.leaf_vpbl);
+ pci_free_consistent(nesdev->pcidev, 8192, root_vpbl.pbl_vbase,
+ root_vpbl.pbl_pbase);
+ }
+
+ return (ibmr);
+ break;
+ case IWNES_MEMREG_TYPE_QP:
+ return (ERR_PTR(-ENOSYS));
+ break;
+ case IWNES_MEMREG_TYPE_CQ:
+ nespbl = kmalloc(sizeof(*nespbl), GFP_KERNEL);
+ if (!nespbl) {
+ dprintk("%s: Unable to allocate PBL\n", __FUNCTION__);
+ return (ERR_PTR(-ENOMEM));
+ }
+ memset(nespbl, 0, sizeof(*nespbl));
+ nesmr = kmalloc(sizeof(*nesmr), GFP_KERNEL);
+ if (!nesmr) {
+ kfree(nespbl);
+ dprintk("%s: Unable to allocate nesmr\n", __FUNCTION__);
+ return (ERR_PTR(-ENOMEM));
+ }
+ memset(nesmr, 0, sizeof(*nesmr));
+ nes_ucontext = to_nesucontext(pd->uobject->context);
+ pbl_depth = region->length >> PAGE_SHIFT;
+ pbl_depth += (region->length & ~PAGE_MASK) ? 1 : 0;
+ nespbl->pbl_size = pbl_depth*sizeof(u64);
+ dprintk("%s: Attempting to allocate CQ PBL memory, %u bytes, %u entries.\n",
+ __FUNCTION__, nespbl->pbl_size, pbl_depth);
+ pbl = pci_alloc_consistent(nesdev->pcidev, nespbl->pbl_size,
+ &nespbl->pbl_pbase);
+ if (!pbl) {
+ kfree(nesmr);
+ kfree(nespbl);
+ dprintk("%s: Unable to allocate cq PBL memory\n", __FUNCTION__);
+ return (ERR_PTR(-ENOMEM));
+ }
+
+ nespbl->pbl_vbase = pbl;
+ nespbl->user_base = region->user_base;
+ dprintk("%s: Allocated CQ PBL memory, %u bytes, pbl_pbase=%p,"
+ " pbl_vbase=%p user_base=0x%lx\n",
+ __FUNCTION__, nespbl->pbl_size, (void *)nespbl->pbl_pbase,
+ (void*)nespbl->pbl_vbase, nespbl->user_base);
+
+ list_for_each_entry(chunk, ®ion->chunk_list, list) {
+ for (j = 0; j < chunk->nmap; ++j) {
+ *pbl = cpu_to_le64((u64)sg_dma_address(&chunk->page_list[j]));
+ /* dprintk("%s: pbl=%p, *pbl=0x%016llx\n", __FUNCTION__, pbl, *pbl); */
+ pbl++;
+ }
+ }
+ list_add_tail(&nespbl->list, &nes_ucontext->cq_reg_mem_list);
+ nesmr->ibmr.rkey = -1;
+ nesmr->ibmr.lkey = -1;
+ nesmr->mode = IWNES_MEMREG_TYPE_CQ;
+ return (&nesmr->ibmr);
+ break;
+ }
+
+ return (ERR_PTR(-ENOSYS));
+}
+
+
+/**
+ * nes_dereg_mr
+ */
+static int nes_dereg_mr(struct ib_mr *ib_mr)
+{
+ struct nes_mr *nesmr = to_nesmr(ib_mr);
+ struct nes_vnic *nesvnic = to_nesvnic(ib_mr->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ u16 major_code;
+ u16 minor_code;
+
+ dprintk("%s:%u ib_mr=%p, rkey = 0x%08X, lkey = 0x%08X, mode = %u\n",
+ __FUNCTION__, __LINE__, ib_mr, ib_mr->rkey, ib_mr->lkey, nesmr->mode);
+
+ if (nesmr->mode != IWNES_MEMREG_TYPE_MEM) {
+ kfree(nesmr);
+ return (0);
+ }
+
+ /* Deallocate the region with the adapter */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ if (0 != nesmr->pbls_used) {
+ if (nesmr->pbl_4k) {
+ nesadapter->free_4kpbl += nesmr->pbls_used;
+ if (nesadapter->free_4kpbl > nesadapter->max_4kpbl) {
+ printk(KERN_ERR PFX "free 4KB PBLs(%u) has exceeded the max(%u)\n",
+ nesadapter->free_4kpbl, nesadapter->max_4kpbl);
+ }
+ } else {
+ nesadapter->free_256pbl += nesmr->pbls_used;
+ if (nesadapter->free_256pbl > nesadapter->max_256pbl) {
+ printk(KERN_ERR PFX "free 256B PBLs(%u) has exceeded the max(%u)\n",
+ nesadapter->free_256pbl, nesadapter->max_256pbl);
+ }
+ }
+ }
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_DEALLOCATE_STAG | NES_CQP_STAG_VA_TO |
+ NES_CQP_STAG_DEALLOC_PBLS | NES_CQP_STAG_MR;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_PBL_LEN_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_STAG_WQE_STAG_IDX] = ib_mr->rkey;
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("%s: Waiting for deallocate STag 0x%08X completed\n",
+ __FUNCTION__, ib_mr->rkey);
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s: Deallocate STag 0x%08X completed, wait_event_timeout ret = %u,"
+ " CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ __FUNCTION__, ib_mr->rkey, ret, cqp_request->major_code, cqp_request->minor_code);
+
+ nes_free_resource(nesadapter, nesadapter->allocated_mrs,
+ (ib_mr->rkey & 0x0fffff00) >> 8);
+
+ kfree(nesmr);
+
+ major_code = cqp_request->major_code;
+ minor_code = cqp_request->minor_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret) {
+ dprintk(KERN_ERR PFX "%s:%u Timeout waiting to destroy STag,"
+ " ib_mr=%p, rkey = 0x%08X\n",
+ __FUNCTION__, __LINE__, ib_mr, ib_mr->rkey);
+ return(-ETIME);
+ } else if (major_code) {
+ dprintk(KERN_ERR PFX "%s:%u Error (0x%04X:0x%04X) while attempting"
+ " to destroy STag, ib_mr=%p, rkey = 0x%08X\n",
+ __FUNCTION__, __LINE__, major_code, minor_code,
+ ib_mr, ib_mr->rkey);
+ return(-EIO);
+ } else
+ return (0);
+}
+
+
+/**
+ * show_rev
+ */
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct nes_ib_device *nesibdev =
+ container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (sprintf(buf, "%x\n", nesvnic->nesdev->nesadapter->hw_rev));
+}
+
+
+/**
+ * show_fw_ver
+ */
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct nes_ib_device *nesibdev =
+ container_of(cdev, struct nes_ib_device, ibdev.class_dev);
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (sprintf(buf, "%x.%x.%x\n",
+ (int)(nesvnic->nesdev->nesadapter->fw_ver >> 32),
+ (int)(nesvnic->nesdev->nesadapter->fw_ver >> 16) & 0xffff,
+ (int)(nesvnic->nesdev->nesadapter->fw_ver & 0xffff)));
+}
+
+
+/**
+ * show_hca
+ */
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (sprintf(buf, "NES020\n"));
+}
+
+
+/**
+ * show_board
+ */
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (sprintf(buf, "%.*s\n", 32, "NES020 Board ID"));
+}
+
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *nes_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
+
+/**
+ * nes_query_qp
+ */
+static int nes_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+
+ attr->qp_access_flags = 0;
+ attr->cap.max_send_wr = nesqp->hwqp.sq_size;
+ attr->cap.max_recv_wr = nesqp->hwqp.rq_size;
+ attr->cap.max_recv_sge = 1;
+ attr->cap.max_inline_data = 0; /* 64?*/
+
+ init_attr->event_handler = nesqp->ibqp.event_handler;
+ init_attr->qp_context = nesqp->ibqp.qp_context;
+ init_attr->send_cq = nesqp->ibqp.send_cq;
+ init_attr->recv_cq = nesqp->ibqp.recv_cq;
+ init_attr->srq = nesqp->ibqp.srq = nesqp->ibqp.srq;
+ init_attr->cap = attr->cap;
+
+ dprintk("%s:%u Leaving\n", __FUNCTION__, __LINE__);
+
+ return (0);
+}
+
+
+/**
+ * nes_hw_modify_qp
+ */
+int nes_hw_modify_qp(struct nes_device *nesdev, struct nes_qp *nesqp, u32 next_iwarp_state, u32 wait_completion)
+{
+ u64 u64temp;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ /* struct iw_cm_id *cm_id = nesqp->cm_id; */
+ /* struct iw_cm_event cm_event; */
+ struct nes_cqp_request *cqp_request;
+ unsigned long flags;
+ int ret;
+ u16 major_code;
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ dprintk("%s:%u: QP%u, refcount = %d\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ if (wait_completion) {
+ cqp_request->waiting = 1;
+ } else {
+ cqp_request->waiting = 0;
+ }
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_MODIFY_QP | NES_CQP_QP_TYPE_IWARP | next_iwarp_state;
+ dprintk("%s:%u: using next_iwarp_state=%08x, wqe_words=%08x\n",
+ __FUNCTION__, __LINE__,
+ next_iwarp_state, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = nesqp->hwqp.qp_id;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nesqp->nesqp_context_pbase;
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_LOW_IDX] = (u32)u64temp;
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_HIGH_IDX] = (u32)(u64temp >> 32);
+
+
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ /* Wait for CQP */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ if (wait_completion) {
+ /* dprintk("Waiting for modify iWARP QP%u to complete.\n", nesqp->hwqp.qp_id); */
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s:%u: Modify iwarp QP%u completed, wait_event_timeout ret=%u, "
+ "CQP Major:Minor codes = 0x%04X:0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, ret, cqp_request->major_code,
+ cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (major_code) {
+ dprintk("%s:%u: Modify iwarp QP%u failed"
+ "CQP Major:Minor codes = 0x%04X:0x%04X, intended next state = 0x%08X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, cqp_request->major_code,
+ cqp_request->minor_code, next_iwarp_state);
+ }
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret)
+ return(-ETIME);
+ else if (major_code)
+ return(-EIO);
+ else
+ return (0);
+ } else {
+ return (0);
+ }
+}
+
+
+/**
+ * nes_modify_qp
+ */
+int nes_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ /* u32 cqp_head; */
+ /* u32 counter; */
+ u32 next_iwarp_state = 0;
+ int err;
+ unsigned long qplockflags;
+ int ret;
+ u16 original_last_aeq;
+ u8 issue_modify_qp = 0;
+ u8 issue_disconnect = 0;
+ u8 dont_wait = 0;
+
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+
+ dprintk("%s:QP%u: QP State = %u, cur QP State = %u, iwarp_state = 0x%X, refcount = %d. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id, attr->qp_state, nesqp->ibqp_state,
+ nesqp->iwarp_state, atomic_read(&nesqp->refcount));
+ dprintk("%s:QP%u: hw_iwarp_state=0x%X, hw_tcp_state=0x%X, QP Access Flags=0x%X,"
+ " attr_mask = 0x%0x. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id, nesqp->hw_iwarp_state,
+ nesqp->hw_tcp_state, attr->qp_access_flags, attr_mask);
+
+ if (attr_mask & IB_QP_STATE) {
+ switch (attr->qp_state) {
+ case IB_QPS_INIT:
+ dprintk("%s:QP%u: new state = init. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_RTR:
+ dprintk("%s:QP%u: new state = rtr. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+ if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_IDLE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_IDLE;
+ issue_modify_qp = 1;
+ break;
+ case IB_QPS_RTS:
+ dprintk("%s:QP%u: new state = rts. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+ if (nesqp->iwarp_state>(u32)NES_CQP_QP_IWARP_STATE_RTS) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ if (nesqp->cm_id == NULL) {
+ dprintk("%s:QP%u: Failing attempt to move QP to RTS without a CM_ID. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_RTS;
+ if (nesqp->iwarp_state != NES_CQP_QP_IWARP_STATE_RTS)
+ next_iwarp_state |= NES_CQP_QP_CONTEXT_VALID |
+ NES_CQP_QP_ARP_VALID | NES_CQP_QP_ORD_VALID;
+ issue_modify_qp = 1;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_ESTABLISHED;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_RTS;
+ nesqp->hte_added = 1;
+ break;
+ case IB_QPS_SQD:
+ issue_modify_qp = 1;
+ dprintk("%s:QP%u: new state=closing. SQ head=%u, SQ tail=%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, nesqp->hwqp.sq_head,
+ nesqp->hwqp.sq_tail);
+ if (nesqp->iwarp_state==(u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return 0;
+ } else {
+ if (nesqp->iwarp_state > (u32)NES_CQP_QP_IWARP_STATE_CLOSING) {
+ dprintk("%s:QP%u: State change to closing ignored due to current iWARP state\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ if (nesqp->hw_iwarp_state != NES_AEQE_IWARP_STATE_RTS) {
+ dprintk("%s:QP%u: State change to closing already done based on hw state.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ issue_modify_qp = 0;
+ nesqp->in_disconnect = 0;
+ }
+ switch (nesqp->hw_iwarp_state) {
+ case NES_AEQE_IWARP_STATE_CLOSING:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ case NES_AEQE_IWARP_STATE_TERMINATE:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ break;
+ case NES_AEQE_IWARP_STATE_ERROR:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+ break;
+ default:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ nesqp->in_disconnect = 1;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+ break;
+ }
+ }
+ break;
+ case IB_QPS_SQE:
+ dprintk("%s:QP%u: new state = terminate. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+ if (nesqp->iwarp_state>=(u32)NES_CQP_QP_IWARP_STATE_TERMINATE) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+ issue_modify_qp = 1;
+ nesqp->in_disconnect = 1;
+ break;
+ case IB_QPS_ERR:
+ case IB_QPS_RESET:
+ if (nesqp->iwarp_state==(u32)NES_CQP_QP_IWARP_STATE_ERROR) {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ }
+ dprintk("%s:QP%u: new state = error. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR;
+ /* next_iwarp_state = (NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000); */
+ if (nesqp->hte_added) {
+ dprintk("%s:%u: set CQP_QP_DEL_HTE\n", __FUNCTION__, __LINE__);
+ next_iwarp_state |= NES_CQP_QP_DEL_HTE;
+ nesqp->hte_added = 0;
+ }
+ if ((nesqp->hw_tcp_state > NES_AEQE_TCP_STATE_CLOSED) &&
+ (nesqp->hw_tcp_state != NES_AEQE_TCP_STATE_TIME_WAIT)) {
+ next_iwarp_state |= NES_CQP_QP_RESET;
+ nesqp->in_disconnect = 1;
+ } else {
+ dprintk("%s:%u:QP%u NOT setting NES_CQP_QP_RESET since TCP state = %u\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, nesqp->hw_tcp_state);
+ dont_wait = 1;
+ }
+ issue_modify_qp = 1;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
+ break;
+ default:
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_rem_ref(&nesqp->ibqp);
+ return (-EINVAL);
+ break;
+ }
+
+ nesqp->ibqp_state = attr->qp_state;
+ if (((nesqp->iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) ==
+ (u32)NES_CQP_QP_IWARP_STATE_RTS) &&
+ ((next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK) >
+ (u32)NES_CQP_QP_IWARP_STATE_RTS)) {
+ nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+ dprintk("%s:%u: Change nesqp->iwarp_state=%08x\n",
+ __FUNCTION__, __LINE__, nesqp->iwarp_state);
+ issue_disconnect = 1;
+ } else {
+ nesqp->iwarp_state = next_iwarp_state & NES_CQP_QP_IWARP_STATE_MASK;
+ dprintk("%s:%u: Change nesqp->iwarp_state=%08x\n",
+ __FUNCTION__, __LINE__, nesqp->iwarp_state);
+ }
+ }
+
+ if (attr_mask & IB_QP_ACCESS_FLAGS) {
+ if (attr->qp_access_flags & IB_ACCESS_LOCAL_WRITE) {
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+ NES_QPCONTEXT_MISC_RDMA_READ_EN;
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) {
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_RDMA_WRITE_EN;
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) {
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_RDMA_READ_EN;
+ issue_modify_qp = 1;
+ }
+ if (attr->qp_access_flags & IB_ACCESS_MW_BIND) {
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_WBIND_EN;
+ issue_modify_qp = 1;
+ }
+
+ if (nesqp->user_mode) {
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_RDMA_WRITE_EN |
+ NES_QPCONTEXT_MISC_RDMA_READ_EN;
+ issue_modify_qp = 1;
+ }
+ }
+
+ original_last_aeq = nesqp->last_aeq;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+
+ dprintk("%s[%u]: issue_modify_qp=%u\n", __FUNCTION__, __LINE__, issue_modify_qp);
+
+ ret = 0;
+ if (issue_modify_qp) {
+ dprintk("%s[%u]: call nes_hw_modify_qp\n", __FUNCTION__, __LINE__);
+ ret = nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 1);
+ if (ret)
+ dprintk("%s[%u]: nes_hw_modify_qp (next_iwarp_state = 0x%08X)"
+ " failed for QP%u.\n",
+ __FUNCTION__, __LINE__, next_iwarp_state, nesqp->hwqp.qp_id);
+
+ }
+
+ if ((issue_modify_qp) && (nesqp->ibqp_state > IB_QPS_RTS)) {
+ dprintk("%s%u: QP%u Issued ModifyQP refcount (%d),"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id,
+ atomic_read(&nesqp->refcount), original_last_aeq, nesqp->last_aeq);
+ if ((!ret) ||
+ ((original_last_aeq != NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) &&
+ (ret))) {
+ if (dont_wait) {
+ if (nesqp->cm_id) {
+ dprintk("%s%u: QP%u Queuing fake disconnect for QP refcount (%d),"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id,
+ atomic_read(&nesqp->refcount), original_last_aeq,
+ nesqp->last_aeq);
+ /* this one is for the cm_disconnect thread */
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ } else {
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ /* These two are for the timer thread */
+ nes_add_ref(&nesqp->ibqp);
+ nesqp->cm_id->add_ref(nesqp->cm_id);
+ dprintk("%s%u: QP%u Not decrementing QP refcount (%d),"
+ " need ae to finish up, original_last_aeq = 0x%04X."
+ " last_aeq = 0x%04X, scheduling timer.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id,
+ atomic_read(&nesqp->refcount), original_last_aeq,
+ nesqp->last_aeq);
+ schedule_nes_timer(nesqp->cm_node_p, (struct sk_buff *) nesqp, NES_TIMER_TYPE_CLOSE, 1);
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ dprintk("%s%u: QP%u Not decrementing QP refcount (%d),"
+ " need ae to finish up, original_last_aeq = 0x%04X."
+ " last_aeq = 0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id,
+ atomic_read(&nesqp->refcount), original_last_aeq,
+ nesqp->last_aeq);
+ }
+ }
+ } else {
+ dprintk("%s%u: QP%u Decrementing QP refcount (%d), No ae to finish up,"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id,
+ atomic_read(&nesqp->refcount), original_last_aeq, nesqp->last_aeq);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ } else {
+ dprintk("%s%u: QP%u Decrementing QP refcount (%d), No ae to finish up,"
+ " original_last_aeq = 0x%04X. last_aeq = 0x%04X.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
+ original_last_aeq, nesqp->last_aeq);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+
+ err = 0;
+
+ dprintk("%s: QP%u Leaving\n", __FUNCTION__, nesqp->hwqp.qp_id);
+
+ return (err);
+}
+
+
+/**
+ * nes_muticast_attach
+ */
+static int nes_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (-ENOSYS);
+}
+
+
+/**
+ * nes_multicast_detach
+ */
+static int nes_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (-ENOSYS);
+}
+
+
+/**
+ * nes_process_mad
+ */
+static int nes_process_mad(struct ib_device *ibdev, int mad_flags,
+ u8 port_num, struct ib_wc *in_wc, struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (-ENOSYS);
+}
+
+
+/**
+ * nes_post_send
+ */
+static int nes_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+ struct ib_send_wr **bad_wr)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ u32 qsize = nesqp->hwqp.sq_size;
+ struct nes_hw_qp_wqe *wqe;
+ unsigned long flags = 0;
+ u32 head;
+ u32 wqe_misc = 0;
+ int err = 0;
+ u32 wqe_count = 0;
+ u32 counter;
+ int sge_index;
+ u32 total_payload_length = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return (-EINVAL);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.sq_head;
+
+ while (ib_wr) {
+ /* Check for SQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.sq_tail) % qsize) == (qsize - 1)) {
+ err = -EINVAL;
+ break;
+ }
+
+ wqe = &nesqp->hwqp.sq_vbase[head];
+ /* dprintk("%s:processing sq wqe for QP%u at %p, head = %u.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, wqe, head); */
+ *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX]) =
+ ib_wr->wr_id;
+ *((struct nes_qp **)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX] |= head;
+
+ switch (ib_wr->opcode) {
+ case IB_WR_SEND:
+ if (ib_wr->send_flags & IB_SEND_SOLICITED) {
+ wqe_misc = NES_IWARP_SQ_OP_SENDSE;
+ } else {
+ wqe_misc = NES_IWARP_SQ_OP_SEND;
+ }
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+ }
+ if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+ (ib_wr->sg_list[0].length <= 64)) {
+ memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+ (void *)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ ib_wr->sg_list[0].length;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] |=
+ NES_IWARP_SQ_WQE_IMM_DATA;
+ } else {
+ total_payload_length = 0;
+ for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)ib_wr->sg_list[sge_index].addr);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)(ib_wr->sg_list[sge_index].addr>>32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].length);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].lkey);
+ total_payload_length += ib_wr->sg_list[sge_index].length;
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ cpu_to_le32(total_payload_length);
+ }
+
+ break;
+ case IB_WR_RDMA_WRITE:
+ wqe_misc = NES_IWARP_SQ_OP_RDMAW;
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ dprintk("%s:%u: Exceeded max sge, ib_wr=%u, max=%u\n",
+ __FUNCTION__, __LINE__, ib_wr->num_sge,
+ nesdev->nesadapter->max_sge);
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ wqe_misc |= NES_IWARP_SQ_WQE_LOCAL_FENCE;
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_STAG_IDX] =
+ cpu_to_le32(ib_wr->wr.rdma.rkey);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX] =
+ cpu_to_le32(ib_wr->wr.rdma.remote_addr);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX] =
+ cpu_to_le32((u32)(ib_wr->wr.rdma.remote_addr >> 32));
+
+ if ((ib_wr->send_flags & IB_SEND_INLINE) &&
+ (ib_wr->sg_list[0].length <= 64)) {
+ memcpy(&wqe->wqe_words[NES_IWARP_SQ_WQE_IMM_DATA_START_IDX],
+ (void *)ib_wr->sg_list[0].addr, ib_wr->sg_list[0].length);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ ib_wr->sg_list[0].length;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] |=
+ NES_IWARP_SQ_WQE_IMM_DATA;
+ } else {
+ total_payload_length = 0;
+ for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)ib_wr->sg_list[sge_index].addr);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)(ib_wr->sg_list[sge_index].addr>>32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].length);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].lkey);
+ total_payload_length += ib_wr->sg_list[sge_index].length;
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ cpu_to_le32(total_payload_length);
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] =
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX];
+ break;
+ case IB_WR_RDMA_READ:
+ /* IWarp only supports 1 sge for RDMA reads */
+ if (ib_wr->num_sge > 1) {
+ dprintk("%s:%u: Exceeded max sge, ib_wr=%u, max=1\n",
+ __FUNCTION__, __LINE__, ib_wr->num_sge);
+ err = -EINVAL;
+ break;
+ }
+ wqe_misc = NES_IWARP_SQ_OP_RDMAR;
+
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX] =
+ cpu_to_le32(ib_wr->wr.rdma.remote_addr);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX] =
+ cpu_to_le32((u32)(ib_wr->wr.rdma.remote_addr >> 32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_STAG_IDX] =
+ cpu_to_le32(ib_wr->wr.rdma.rkey);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX] =
+ cpu_to_le32(ib_wr->sg_list->length);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32(ib_wr->sg_list->addr);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)(ib_wr->sg_list->addr >> 32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] =
+ cpu_to_le32(ib_wr->sg_list->lkey);
+ break;
+ default:
+ /* error */
+ err = -EINVAL;
+ break;
+ }
+
+ if (ib_wr->send_flags & IB_SEND_SIGNALED) {
+ dprintk("%s:%u: Setting SQ_WQE_SIGNALED_COMPL\n",
+ __FUNCTION__, __LINE__);
+ wqe_misc |= NES_IWARP_SQ_WQE_SIGNALED_COMPL;
+ }
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(wqe_misc);
+
+ ib_wr = ib_wr->next;
+ head++;
+ wqe_count++;
+ if (head >= qsize)
+ head = 0;
+
+ }
+
+ nesqp->hwqp.sq_head = head;
+ barrier();
+ while (wqe_count) {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs + NES_WQE_ALLOC,
+ (counter << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+ }
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ if (err)
+ *bad_wr = ib_wr;
+ return(err);
+}
+
+
+/**
+ * nes_post_recv
+ */
+static int nes_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+ struct ib_recv_wr **bad_wr)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibqp->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_qp *nesqp = to_nesqp(ibqp);
+ u32 qsize = nesqp->hwqp.rq_size;
+ struct nes_hw_qp_wqe *wqe;
+ unsigned long flags = 0;
+ u32 head;
+ int err = 0;
+ u32 wqe_count = 0;
+ u32 counter;
+ int sge_index;
+ u32 total_payload_length;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ if (nesqp->ibqp_state > IB_QPS_RTS)
+ return (-EINVAL);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+
+ head = nesqp->hwqp.rq_head;
+
+ while (ib_wr) {
+ if (ib_wr->num_sge > nesdev->nesadapter->max_sge) {
+ err = -EINVAL;
+ break;
+ }
+ /* Check for RQ overflow */
+ if (((head + (2 * qsize) - nesqp->hwqp.rq_tail) % qsize) == (qsize - 1)) {
+ err = -EINVAL;
+ break;
+ }
+
+ dprintk("%s: ibwr sge count = %u.\n", __FUNCTION__, ib_wr->num_sge);
+ wqe = &nesqp->hwqp.rq_vbase[head];
+
+ /* dprintk("%s:QP%u:processing rq wqe at %p, head = %u.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, wqe, head); */
+ *((u64 *)&wqe->wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]) =
+ ib_wr->wr_id;
+ *((struct nes_qp **)&wqe->wqe_words[NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX]) =
+ nesqp;
+ wqe->wqe_words[NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX] |= head;
+
+ total_payload_length = 0;
+ for (sge_index=0; sge_index < ib_wr->num_sge; sge_index++) {
+ wqe->wqe_words[NES_IWARP_RQ_WQE_FRAG0_LOW_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)ib_wr->sg_list[sge_index].addr);
+ wqe->wqe_words[NES_IWARP_RQ_WQE_FRAG0_HIGH_IDX+(sge_index*4)] =
+ cpu_to_le32((u32)(ib_wr->sg_list[sge_index].addr >> 32));
+ wqe->wqe_words[NES_IWARP_RQ_WQE_LENGTH0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].length);
+ wqe->wqe_words[NES_IWARP_RQ_WQE_STAG0_IDX+(sge_index*4)] =
+ cpu_to_le32(ib_wr->sg_list[sge_index].lkey);
+ total_payload_length += ib_wr->sg_list[sge_index].length;
+ }
+ wqe->wqe_words[NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX] =
+ cpu_to_le32(total_payload_length);
+
+ ib_wr = ib_wr->next;
+ head++;
+ wqe_count++;
+ if (head >= qsize)
+ head = 0;
+ }
+
+ nesqp->hwqp.rq_head = head;
+ barrier();
+ while (wqe_count) {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter<<24) | nesqp->hwqp.qp_id);
+ }
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+
+ if (err)
+ *bad_wr = ib_wr;
+ return (err);
+}
+
+
+/**
+ * nes_poll_cq
+ */
+static int nes_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+ u64 wrid;
+ /* u64 u64temp; */
+ struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_cq *nescq = to_nescq(ibcq);
+ struct nes_qp *nesqp;
+ struct nes_hw_cqe cqe;
+ unsigned long flags = 0;
+ u32 head;
+ u32 wq_tail;
+ u32 cq_size;
+ u32 cqe_count=0;
+ u32 wqe_index;
+ /* u32 counter; */
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ spin_lock_irqsave(&nescq->lock, flags);
+
+ head = nescq->hw_cq.cq_head;
+ cq_size = nescq->hw_cq.cq_size;
+
+ while (cqe_count<num_entries) {
+ if (le32_to_cpu(nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
+ NES_CQE_VALID) {
+ cqe = nescq->hw_cq.cq_vbase[head];
+ nescq->hw_cq.cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+ wqe_index = cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] &
+ (nesdev->nesadapter->max_qp_wr - 1);
+ cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX] &= ~(NES_SW_CONTEXT_ALIGN-1);
+ barrier();
+ /* parse CQE, get completion context from WQE (either rq or sq */
+ nesqp = *((struct nes_qp **)&cqe.cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+ memset(entry, 0, sizeof *entry);
+ if (0 == cqe.cqe_words[NES_CQE_ERROR_CODE_IDX]) {
+ entry->status = IB_WC_SUCCESS;
+ } else {
+ entry->status = IB_WC_WR_FLUSH_ERR;
+ }
+
+ entry->qp = &nesqp->ibqp;
+ entry->src_qp = nesqp->hwqp.qp_id;
+
+ if (le32_to_cpu(cqe.cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_SQ) {
+ if (nesqp->skip_lsmm) {
+ nesqp->skip_lsmm = 0;
+ wq_tail = nesqp->hwqp.sq_tail++;
+ }
+
+ /* Working on a SQ Completion*/
+ wq_tail = wqe_index;
+ nesqp->hwqp.sq_tail = (wqe_index+1)&(nesqp->hwqp.sq_size - 1);
+ wrid = *((u64 *)&nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX]);
+ entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX]);
+
+ switch (le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_MISC_IDX]) & 0x3f) {
+ case NES_IWARP_SQ_OP_RDMAW:
+ dprintk("%s: Operation = RDMA WRITE.\n", __FUNCTION__);
+ entry->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case NES_IWARP_SQ_OP_RDMAR:
+ dprintk("%s: Operation = RDMA READ.\n", __FUNCTION__);
+ entry->opcode = IB_WC_RDMA_READ;
+ entry->byte_len = le32_to_cpu(nesqp->hwqp.sq_vbase[wq_tail].
+ wqe_words[NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX]);
+ break;
+ case NES_IWARP_SQ_OP_SENDINV:
+ case NES_IWARP_SQ_OP_SENDSEINV:
+ case NES_IWARP_SQ_OP_SEND:
+ case NES_IWARP_SQ_OP_SENDSE:
+ dprintk("%s: Operation = Send.\n", __FUNCTION__);
+ entry->opcode = IB_WC_SEND;
+ break;
+ }
+ } else {
+ /* Working on a RQ Completion*/
+ wq_tail = wqe_index;
+ nesqp->hwqp.rq_tail = (wqe_index+1)&(nesqp->hwqp.rq_size - 1);
+ entry->byte_len = le32_to_cpu(cqe.cqe_words[NES_CQE_PAYLOAD_LENGTH_IDX]);
+ wrid = *((u64 *)&nesqp->hwqp.rq_vbase[wq_tail].
+ wqe_words[NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX]);
+ entry->opcode = IB_WC_RECV;
+ }
+ entry->wr_id = wrid;
+
+ if (++head >= cq_size)
+ head = 0;
+ cqe_count++;
+ nescq->polled_completions++;
+ if ((nescq->polled_completions > (cq_size/2)) ||
+ (nescq->polled_completions == 255)) {
+ dprintk("%s: CQ%u Issuing CQE Allocate since more than half of cqes"
+ " are pending %u of %u.\n",
+ __FUNCTION__, nescq->hw_cq.cq_number,
+ nescq->polled_completions, cq_size);
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+ nescq->polled_completions = 0;
+ }
+ entry++;
+ } else
+ break;
+ }
+
+ if (nescq->polled_completions) {
+ /* dprintk("%s: CQ%u Issuing CQE Allocate for %u cqes.\n",
+ __FUNCTION__, nescq->hw_cq.cq_number, nescq->polled_completions); */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->hw_cq.cq_number | (nescq->polled_completions << 16));
+ nescq->polled_completions = 0;
+ }
+
+ nescq->hw_cq.cq_head = head;
+ dprintk("%s: Reporting %u completions for CQ%u.\n", __FUNCTION__, cqe_count,
+ nescq->hw_cq.cq_number);
+
+ spin_unlock_irqrestore(&nescq->lock, flags);
+
+ return (cqe_count);
+}
+
+
+/**
+ * nes_req_notify_cq
+ */
+static int nes_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+{
+ struct nes_vnic *nesvnic = to_nesvnic(ibcq->device);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_cq *nescq = to_nescq(ibcq);
+ u32 cq_arm;
+
+ dprintk("%s: Requesting notification for CQ%u.\n",
+ __FUNCTION__, nescq->hw_cq.cq_number);
+
+ cq_arm = nescq->hw_cq.cq_number;
+ if (notify == IB_CQ_NEXT_COMP)
+ cq_arm |= NES_CQE_ALLOC_NOTIFY_NEXT;
+ else if (notify == IB_CQ_SOLICITED)
+ cq_arm |= NES_CQE_ALLOC_NOTIFY_SE;
+ else
+ return (-EINVAL);
+
+ /* dprintk("%s: Arming CQ%u, command = 0x%08X.\n",
+ __FUNCTION__, nescq->hw_cq.cq_number, cq_arm); */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq_arm);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+ return (0);
+}
+
+
+/**
+ * nes_init_ofa_device
+ */
+struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev)
+{
+ struct nes_ib_device *nesibdev;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ nesibdev = (struct nes_ib_device *)ib_alloc_device(sizeof(struct nes_ib_device));
+ if (nesibdev == NULL) {
+ return(NULL);
+ }
+ strlcpy(nesibdev->ibdev.name, "nes%d", IB_DEVICE_NAME_MAX);
+ nesibdev->ibdev.owner = THIS_MODULE;
+
+ nesibdev->ibdev.node_type = RDMA_NODE_RNIC;
+ memset(&nesibdev->ibdev.node_guid, 0, sizeof(nesibdev->ibdev.node_guid));
+ memcpy(&nesibdev->ibdev.node_guid, netdev->dev_addr, 6);
+
+ nesibdev->ibdev.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_AH) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_AH) |
+ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_MW) |
+ (1ull << IB_USER_VERBS_CMD_BIND_MW) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_MW) |
+ (1ull << IB_USER_VERBS_CMD_POST_RECV) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND);
+
+ nesibdev->ibdev.phys_port_cnt = 1;
+ nesibdev->ibdev.dma_device = &nesdev->pcidev->dev;
+ nesibdev->ibdev.class_dev.dev = &nesdev->pcidev->dev;
+ nesibdev->ibdev.query_device = nes_query_device;
+ nesibdev->ibdev.query_port = nes_query_port;
+ nesibdev->ibdev.modify_port = nes_modify_port;
+ nesibdev->ibdev.query_pkey = nes_query_pkey;
+ nesibdev->ibdev.query_gid = nes_query_gid;
+ nesibdev->ibdev.alloc_ucontext = nes_alloc_ucontext;
+ nesibdev->ibdev.dealloc_ucontext = nes_dealloc_ucontext;
+ nesibdev->ibdev.mmap = nes_mmap;
+ nesibdev->ibdev.alloc_pd = nes_alloc_pd;
+ nesibdev->ibdev.dealloc_pd = nes_dealloc_pd;
+ nesibdev->ibdev.create_ah = nes_create_ah;
+ nesibdev->ibdev.destroy_ah = nes_destroy_ah;
+ nesibdev->ibdev.create_qp = nes_create_qp;
+ nesibdev->ibdev.modify_qp = nes_modify_qp;
+ nesibdev->ibdev.query_qp = nes_query_qp;
+ nesibdev->ibdev.destroy_qp = nes_destroy_qp;
+ nesibdev->ibdev.create_cq = nes_create_cq;
+ nesibdev->ibdev.destroy_cq = nes_destroy_cq;
+ nesibdev->ibdev.poll_cq = nes_poll_cq;
+ nesibdev->ibdev.get_dma_mr = nes_get_dma_mr;
+ nesibdev->ibdev.reg_phys_mr = nes_reg_phys_mr;
+ nesibdev->ibdev.reg_user_mr = nes_reg_user_mr;
+ nesibdev->ibdev.dereg_mr = nes_dereg_mr;
+ nesibdev->ibdev.alloc_mw = nes_alloc_mw;
+ nesibdev->ibdev.dealloc_mw = nes_dealloc_mw;
+ nesibdev->ibdev.bind_mw = nes_bind_mw;
+
+ nesibdev->ibdev.alloc_fmr = nes_alloc_fmr;
+ nesibdev->ibdev.unmap_fmr = nes_unmap_fmr;
+ nesibdev->ibdev.dealloc_fmr = nes_dealloc_fmr;
+ nesibdev->ibdev.map_phys_fmr = nes_map_phys_fmr;
+
+ nesibdev->ibdev.attach_mcast = nes_multicast_attach;
+ nesibdev->ibdev.detach_mcast = nes_multicast_detach;
+ nesibdev->ibdev.process_mad = nes_process_mad;
+
+ nesibdev->ibdev.req_notify_cq = nes_req_notify_cq;
+ nesibdev->ibdev.post_send = nes_post_send;
+ nesibdev->ibdev.post_recv = nes_post_recv;
+
+ nesibdev->ibdev.iwcm = kmalloc(sizeof(*nesibdev->ibdev.iwcm), GFP_KERNEL);
+ if (nesibdev->ibdev.iwcm == NULL) {
+ ib_dealloc_device(&nesibdev->ibdev);
+ return(NULL);
+ }
+ nesibdev->ibdev.iwcm->add_ref = nes_add_ref;
+ nesibdev->ibdev.iwcm->rem_ref = nes_rem_ref;
+ nesibdev->ibdev.iwcm->get_qp = nes_get_qp;
+ nesibdev->ibdev.iwcm->connect = nes_connect;
+ nesibdev->ibdev.iwcm->accept = nes_accept;
+ nesibdev->ibdev.iwcm->reject = nes_reject;
+ nesibdev->ibdev.iwcm->create_listen = nes_create_listen;
+ nesibdev->ibdev.iwcm->destroy_listen = nes_destroy_listen;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return(nesibdev);
+}
+
+
+/**
+ * nes_destroy_ofa_device
+ */
+void nes_destroy_ofa_device(struct nes_ib_device *nesibdev)
+{
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+ if (NULL == nesibdev)
+ return;
+
+ nes_unregister_ofa_device(nesibdev);
+
+ kfree(nesibdev->ibdev.iwcm);
+ ib_dealloc_device(&nesibdev->ibdev);
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+}
+
+
+/**
+ * nes_register_ofa_device
+ */
+int nes_register_ofa_device(struct nes_ib_device *nesibdev)
+{
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ int i, ret;
+
+ dprintk("%s: %u: &nesvnic=0x%p : &ibdev=0x%p\n", __FUNCTION__, __LINE__,
+ nesvnic, &nesvnic->nesibdev->ibdev);
+
+ ret = ib_register_device(&nesvnic->nesibdev->ibdev);
+ if (ret) {
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return(ret);
+ }
+
+ dprintk("%s:%u after ib_register_device\n", __FUNCTION__, __LINE__);
+
+ /* Get the resources allocated to this device */
+ nesibdev->max_cq = (nesadapter->max_cq-NES_FIRST_QPN) / nesadapter->port_count;
+ nesibdev->max_mr = nesadapter->max_mr / nesadapter->port_count;
+ nesibdev->max_qp = (nesadapter->max_qp-NES_FIRST_QPN) / nesadapter->port_count;
+ nesibdev->max_pd = nesadapter->max_pd / nesadapter->port_count;
+
+ for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+ dprintk("%s:%u call class_device_create_file\n", __FUNCTION__, __LINE__);
+ ret = class_device_create_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+ if (ret) {
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ while (i > 0) {
+ i--;
+ class_device_remove_file(&nesibdev->ibdev.class_dev,
+ nes_class_attributes[i]);
+ }
+ ib_unregister_device(&nesibdev->ibdev);
+ return(ret);
+ }
+ }
+
+ nesvnic->of_device_registered = 1;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * nes_unregister_ofa_device
+ */
+void nes_unregister_ofa_device(struct nes_ib_device *nesibdev)
+{
+ struct nes_vnic *nesvnic = nesibdev->nesvnic;
+ int i;
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+ if (NULL == nesibdev)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(nes_class_attributes); ++i) {
+ class_device_remove_file(&nesibdev->ibdev.class_dev, nes_class_attributes[i]);
+ }
+
+ if (nesvnic->of_device_registered) {
+ dprintk("%s:%u call ib_unregister_device()\n", __FUNCTION__, __LINE__);
+ ib_unregister_device(&nesibdev->ibdev);
+ }
+
+ nesvnic->of_device_registered = 0;
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+}
+
^ permalink raw reply
* [PATCH 10/14] nes: eeprom, phy, routines
From: ggrundstrom @ 2007-08-08 1:17 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Misc eeprom, phy, debug, etc routines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_utils.c
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_utils.c 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,835 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include "nes.h"
+
+#define BITMASK(X) (1L << (X))
+#define NES_CRC_WID 32
+
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset);
+
+static u32 nesCRCTable[256];
+static u32 nesCRCInitialized = 0;
+
+static u32 nesCRCWidMask(u32);
+static u32 nes_crc_table_gen(u32 *, u32, u32, u32);
+static u32 reflect(u32, u32);
+static u32 byte_swap(u32, u32);
+
+u32 mh_detected;
+
+/**
+ * nes_read_eeprom_values -
+ */
+int nes_read_eeprom_values(struct nes_device *nesdev, struct nes_adapter *nesadapter)
+{
+ u32 mac_addr_low;
+ u16 mac_addr_high;
+ u16 eeprom_data;
+ u16 eeprom_offset;
+ u32 index;
+
+ /* TODO: deal with EEPROM endian issues */
+ if (nesadapter->firmware_eeprom_offset == 0) {
+ /* Read the EEPROM Parameters */
+ eeprom_data = nes_read16_eeprom(nesdev->regs, 0);
+ dprintk("EEPROM Offset 0 = 0x%04X\n", eeprom_data);
+ eeprom_offset = 2 + (((eeprom_data & 0x007f) << 3) <<
+ ((eeprom_data & 0x0080) >> 7));
+ dprintk("Firmware Offset = 0x%04X\n", eeprom_offset);
+ nesadapter->firmware_eeprom_offset = eeprom_offset;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+ if (eeprom_data != 0x5746) {
+ dprintk("Not a valid Firmware Image = 0x%04X\n", eeprom_data);
+ return(-1);
+ }
+
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 2);
+ dprintk("EEPROM Offset %u = 0x%04X\n", eeprom_offset + 2, eeprom_data);
+ eeprom_offset += ((eeprom_data & 0x00ff) << 3) << ((eeprom_data & 0x0100) >> 8);
+ dprintk("Software Offset = 0x%04X\n", eeprom_offset);
+ nesadapter->software_eeprom_offset = eeprom_offset;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("EEPROM Offset %u = 0x%04X\n", eeprom_offset, eeprom_data);
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset + 4);
+ if (eeprom_data != 0x5753) {
+ dprintk("Not a valid Software Image = 0x%04X\n", eeprom_data);
+ return(-1);
+ }
+
+ /* eeprom is valid */
+ eeprom_offset = nesadapter->software_eeprom_offset;
+ eeprom_offset += 8;
+ nesadapter->netdev_max = (u8)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_high = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_low = (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ mac_addr_low <<= 16;
+ mac_addr_low += (u32)nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("Base MAC Address = 0x%04X%08X\n", mac_addr_high, mac_addr_low);
+ dprintk("MAC Address count = %u\n", nesadapter->netdev_max);
+
+ nesadapter->mac_addr_low = mac_addr_low;
+ nesadapter->mac_addr_high = mac_addr_high;
+
+ /* Read the Phy Type array */
+ eeprom_offset += 10;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("PhyType: 0x%04x\n", eeprom_data);
+
+ /* Read the port array */
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ /* port_count is set by soft reset reg */
+ for (index = 0; index < 4; index++) {
+ nesadapter->ports[index] = eeprom_data & 0x000f;
+ eeprom_data >>= 4;
+ }
+ dprintk("port_count = %u, port 0 -> %u, port 1 -> %u, port 2 -> %u, port 3 -> %u\n",
+ nesadapter->port_count,
+ nesadapter->ports[0], nesadapter->ports[1],
+ nesadapter->ports[2], nesadapter->ports[3]);
+
+ eeprom_offset += 46;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->rx_pool_size = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("rx_pool_size = 0x%08X\n", nesadapter->rx_pool_size);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tx_pool_size = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("tx_pool_size = 0x%08X\n", nesadapter->tx_pool_size);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->rx_threshold = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("rx_threshold = 0x%08X\n", nesadapter->rx_threshold);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tcp_timer_core_clk_divisor = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("tcp_timer_core_clk_divisor = 0x%08X\n",
+ nesadapter->tcp_timer_core_clk_divisor);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->iwarp_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("iwarp_config = 0x%08X\n", nesadapter->iwarp_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->cm_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("cm_config = 0x%08X\n", nesadapter->cm_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->sws_timer_config = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("sws_timer_config = 0x%08X\n", nesadapter->sws_timer_config);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->tcp_config1 = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("tcp_config1 = 0x%08X\n", nesadapter->tcp_config1);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->wqm_wat = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("wqm_wat = 0x%08X\n", nesadapter->wqm_wat);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->core_clock = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("core_clock = 0x%08X\n", nesadapter->core_clock);
+
+ eeprom_offset += 2;
+ eeprom_data = nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ eeprom_offset += 2;
+ nesadapter->firmware_version = (((u32)eeprom_data) << 16) +
+ nes_read16_eeprom(nesdev->regs, eeprom_offset);
+ dprintk("firmware_version = 0x%08X\n", nesadapter->firmware_version);
+ }
+
+ nesadapter->phy_index[0] = 4;
+ nesadapter->phy_index[1] = 5;
+ nesadapter->phy_index[2] = 6;
+ nesadapter->phy_index[3] = 7;
+
+ /* TODO: get this from EEPROM */
+ nesdev->base_doorbell_index = 1;
+
+ return (0);
+}
+
+
+/**
+ * nes_read16_eeprom
+ */
+static u16 nes_read16_eeprom(void __iomem *addr, u16 offset)
+{
+ writel(cpu_to_le32(NES_EEPROM_READ_REQUEST + (offset >> 1)),
+ (u8 *)addr + NES_EEPROM_COMMAND);
+
+ do {
+ } while ((le32_to_cpu(readl((u8 *)addr + NES_EEPROM_COMMAND)) &
+ NES_EEPROM_READ_REQUEST));
+
+ return(le16_to_cpu(readw((u8 *)addr + NES_EEPROM_DATA)));
+}
+
+
+/**
+ * nes_write_1G_phy_reg
+ */
+void nes_write_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 data)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 u32temp;
+ u32 counter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x50020000 | data | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_read_1G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 *data)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 u32temp;
+ u32 counter;
+ unsigned long flags;
+
+ /* dprintk("%s: phy addr = %d, mac_index = %d\n",
+ __FUNCTION__, phy_addr, nesdev->mac_index); */
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x60020000 | ((u32)phy_reg << 18) | ((u32)phy_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1)) {
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+ *data = 0xffff;
+ } else {
+ *data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ }
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+}
+
+
+/**
+ * nes_write_10G_phy_reg
+ */
+void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
+ u8 phy_addr, u16 data)
+{
+ u32 dev_addr;
+ u32 port_addr;
+ u32 u32temp;
+ u32 counter;
+
+ dev_addr = 5;
+ port_addr = 0;
+
+ /* set address */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x00020000 | phy_reg | (dev_addr << 18) | (port_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Address phase; Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+
+ /* set data */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x10020000 | data | (dev_addr << 18) | (port_addr << 23));
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Write phase; Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+}
+
+
+/**
+ * nes_read_10G_phy_reg
+ * This routine only issues the read, the data must be read
+ * separately.
+ */
+void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr)
+{
+ u32 dev_addr;
+ u32 port_addr;
+ u32 u32temp;
+ u32 counter;
+
+ dev_addr = 5;
+ port_addr = 0;
+
+ /* set address */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x00020000 | phy_reg | (dev_addr << 18) | (port_addr << 23));
+ /* dprintk("%s: Waiting for MAC Interrupt.\n", __FUNCTION__ ); */
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Address phase; Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+
+ /* issue read */
+ nes_write_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL,
+ 0x30020000 | (dev_addr << 18) | (port_addr << 23));
+ /* dprintk("%s: Waiting for MAC Interrupt...2nd time.\n", __FUNCTION__ ); */
+ for (counter = 0; counter < 100 ; counter++) {
+ udelay(30);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS);
+ if (u32temp & 1) {
+ /* dprintk("Read phase; Phy interrupt status = 0x%X.\n", u32temp); */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS, 1);
+ break;
+ }
+ }
+ if (!(u32temp & 1))
+ dprintk("Phy is not responding. interrupt status = 0x%X.\n", u32temp);
+}
+
+
+/**
+ * nes_arp_table
+ */
+int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 action)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ int arp_index;
+ int err = 0;
+
+ dprintk("%s: nesadapter=%p, ip_addr=%08x, action=%u, next_arp_index=%u\n",
+ __FUNCTION__, nesadapter, ip_addr, action, nesadapter->next_arp_index);
+
+ for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) {
+ if (nesadapter->arp_table[arp_index].ip_addr == ip_addr)
+ break;
+ }
+
+ if (action == NES_ARP_ADD) {
+ if (arp_index != nesadapter->arp_table_size) {
+ return (-1);
+ }
+
+ arp_index = 0;
+ err = nes_alloc_resource(nesadapter, nesadapter->allocated_arps,
+ nesadapter->arp_table_size, &arp_index, &nesadapter->next_arp_index);
+ if (err) {
+ dprintk("%s: nes_alloc_resource returned error = %u\n",
+ __FUNCTION__, err);
+ return (err);
+ }
+ dprintk("%s: ADD, arp_index=%d\n", __FUNCTION__, arp_index);
+
+ nesadapter->arp_table[arp_index].ip_addr = ip_addr;
+ memcpy(nesadapter->arp_table[arp_index].mac_addr, mac_addr, ETH_ALEN);
+ return (arp_index);
+ }
+
+ /* DELETE or RESOLVE */
+ if (arp_index == nesadapter->arp_table_size) {
+ dprintk("%s: mac address not in ARP table - cannot delete or resolve\n",
+ __FUNCTION__);
+ return (-1);
+ }
+
+ if (action == NES_ARP_RESOLVE) {
+ dprintk("%s: RESOLVE, arp_index=%d\n", __FUNCTION__, arp_index);
+ return (arp_index);
+ }
+
+ if (action == NES_ARP_DELETE) {
+ dprintk("%s: DELETE, arp_index=%d\n", __FUNCTION__, arp_index);
+ nesadapter->arp_table[arp_index].ip_addr = 0;
+ memset(nesadapter->arp_table[arp_index].mac_addr, 0x00, ETH_ALEN);
+ nes_free_resource(nesadapter, nesadapter->allocated_arps, arp_index);
+ return (arp_index);
+ }
+
+ return (-1);
+}
+
+
+/**
+ * nes_mh_fix
+ */
+void nes_mh_fix(unsigned long parm)
+{
+ unsigned long flags;
+ struct nes_device *nesdev = (struct nes_device *)parm;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 used_chunks_tx_1;
+ u32 used_chunks_tx_2;
+ u32 mac_tx_frames;
+ u32 mac_tx_pauses;
+ u32 serdes_status;
+ u32 reset_value;
+ u32 tx_control;
+ u32 tx_config;
+ u32 tx_pause_quanta;
+ u32 rx_control;
+ u32 rx_config;
+ u32 mac_exact_match;
+ u32 mpp_debug;
+ u32 i=0;
+
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ if ((nesadapter->mac_sw_state[0] != NES_MAC_SW_IDLE) || (nesadapter->mac_link_down[0])) {
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ return;
+ }
+ nesadapter->mac_sw_state[0] = NES_MAC_SW_MH;
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ do {
+ used_chunks_tx_1 = nes_read_indexed(nesdev, NES_IDX_USED_CHUNKS_TX);
+ if (!used_chunks_tx_1)
+ break;
+ used_chunks_tx_2 = nes_read_indexed(nesdev, NES_IDX_USED_CHUNKS_TX);
+ if (!used_chunks_tx_2)
+ break;
+ if (used_chunks_tx_1 != used_chunks_tx_2)
+ break;
+
+ mac_tx_frames = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_LOW);
+ mac_tx_frames = nes_read_indexed(nesdev, NES_IDX_MAC_TX_FRAMES_LOW);
+ if (mac_tx_frames)
+ break;
+
+ mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000005);
+ mac_tx_pauses = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_FRAMES);
+ if (mac_tx_pauses)
+ break;
+
+ mh_detected++;
+ tx_control = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONTROL);
+ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
+ tx_pause_quanta = nes_read_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA);
+ rx_control = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONTROL);
+ rx_config = nes_read_indexed(nesdev, NES_IDX_MAC_RX_CONFIG);
+ mac_exact_match = nes_read_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM);
+ mpp_debug = nes_read_indexed(nesdev, NES_IDX_MPP_DEBUG);
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, 0x00000000);
+ reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value | 0x0000001d);
+
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
+ & 0x00000040) != 0x00000040) && (i++ < 5000)) {
+ // mdelay(1);
+ }
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+ serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0);
+
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0002222);
+ serdes_status = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_STATUS0);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+
+
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONTROL, tx_control);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
+ nes_write_indexed(nesdev, NES_IDX_MAC_TX_PAUSE_QUANTA, tx_pause_quanta);
+ nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONTROL, rx_control);
+ nes_write_indexed(nesdev, NES_IDX_MAC_RX_CONFIG, rx_config);
+ nes_write_indexed(nesdev, NES_IDX_MAC_EXACT_MATCH_BOTTOM, mac_exact_match);
+ nes_write_indexed(nesdev, NES_IDX_MPP_DEBUG, mpp_debug);
+
+ } while (0);
+
+ nesadapter->mac_sw_state[0] = NES_MAC_SW_IDLE;
+ nesdev->nesadapter->mh_timer.expires = jiffies + (HZ/5);
+ add_timer(&nesdev->nesadapter->mh_timer);
+}
+
+
+/**
+ * nes_dump_mem
+ */
+void nes_dump_mem(void *addr, int length)
+{
+ char xlate[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'a', 'b', 'c', 'd', 'e', 'f'};
+ char *ptr;
+ char hex_buf[80];
+ char ascii_buf[20];
+ int num_char;
+ int num_ascii;
+ int num_hex;
+
+ ptr = addr;
+ if (length > 0x100) {
+ dprintk("Length truncated from %x to %x\n", length, 0x100);
+ length = 0x100;
+ }
+ dprintk("Address=0x%p, length=0x%x (%d)\n", ptr, length, length);
+
+ memset(ascii_buf, 0, 20);
+ memset(hex_buf, 0, 80);
+
+ num_ascii = 0;
+ num_hex = 0;
+ for (num_char = 0; num_char < length; num_char++) {
+ if (num_ascii == 8) {
+ ascii_buf[num_ascii++] = ' ';
+ hex_buf[num_hex++] = '-';
+ hex_buf[num_hex++] = ' ';
+ }
+
+ if (*ptr < 0x20 || *ptr > 0x7e)
+ ascii_buf[num_ascii++] = '.';
+ else
+ ascii_buf[num_ascii++] = *ptr;
+ hex_buf[num_hex++] = xlate[((*ptr & 0xf0) >> 4)];
+ hex_buf[num_hex++] = xlate[*ptr & 0x0f];
+ hex_buf[num_hex++] = ' ';
+ ptr++;
+
+ if (num_ascii >= 17) {
+ /* output line and reset */
+ dprintk(" %s | %s\n", hex_buf, ascii_buf);
+ memset(ascii_buf, 0, 20);
+ memset(hex_buf, 0, 80);
+ num_ascii = 0;
+ num_hex = 0;
+ }
+ }
+
+ /* output the rest */
+ if (num_ascii) {
+ while (num_ascii < 17) {
+ if (num_ascii == 8) {
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ }
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ hex_buf[num_hex++] = ' ';
+ num_ascii++;
+ }
+
+ dprintk(" %s | %s\n", hex_buf, ascii_buf);
+ }
+}
+
+
+/*
+"Everything you wanted to know about CRC algorithms, but were afraid to ask
+ for fear that errors in your understanding might be detected." Version : 3.
+Date : 19 August 1993.
+Author : Ross N. Williams.
+Net : ross@guest.adelaide.edu.au.
+FTP : ftp.adelaide.edu.au/pub/rocksoft/crc_v3.txt
+Company : Rocksoft Pty Ltd.
+Snail : 16 Lerwick Avenue, Hazelwood Park 5066, Australia.
+Fax : +61 8 373-4911 (c/- Internode Systems Pty Ltd).
+Phone : +61 8 379-9217 (10am to 10pm Adelaide Australia time).
+Note : "Rocksoft" is a trademark of Rocksoft Pty Ltd, Australia.
+Status : Copyright (C) Ross Williams, 1993. However, permission is granted to
+ make and distribute verbatim copies of this document provided that this information
+ block and copyright notice is included. Also, the C code modules included in this
+ document are fully public domain.
+
+Thanks : Thanks to Jean-loup Gailly (jloup@chorus.fr) and Mark Adler
+ (me@quest.jpl.nasa.gov) who both proof read this document and picked
+ out lots of nits as well as some big fat bugs.
+
+The current web page for this seems to be http://www.ross.net/crc/crcpaper.html.
+
+*/
+
+/****************************************************************************/
+/* Generate width mask */
+/****************************************************************************/
+/* */
+/* Returns a longword whose value is (2^p_cm->cm_width)-1. */
+/* The trick is to do this portably (e.g. without doing <<32). */
+/* */
+/* Author: Tristan Gross */
+/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */
+/* Ross N. Williams */
+/* http://www.rocksoft.com */
+/* */
+/****************************************************************************/
+
+static u32 nesCRCWidMask (u32 width)
+{
+ return(((1L<<(((u32)width)-1))-1L)<<1)|1L;
+}
+
+
+/****************************************************************************/
+/* Generate CRC table */
+/****************************************************************************/
+/* */
+/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */
+/* Ross N. Williams */
+/* http://www.rocksoft.com */
+/* */
+/****************************************************************************/
+static u32 nes_crc_table_gen ( u32 *pCRCTable,
+ u32 poly,
+ u32 order,
+ u32 reflectIn)
+{
+ u32 i;
+ u32 reg;
+ u32 byte;
+ u32 topbit = BITMASK(NES_CRC_WID-1);
+ u32 tmp;
+
+ for (byte=0;byte<256;byte++) {
+
+ // If we need to creat a reflected table we must reflect the index (byte) and
+ // reflect the final reg
+ tmp = (reflectIn) ? reflect(byte,8): byte;
+
+ reg = tmp << (NES_CRC_WID-8);
+
+ for (i=0; i<8; i++) {
+ if (reg & topbit) {
+ reg = (reg << 1) ^ poly;
+ } else {
+ reg <<= 1;
+ }
+ }
+
+ reg = (reflectIn) ? reflect(reg,order): reg;
+ pCRCTable[byte] = reg & nesCRCWidMask(NES_CRC_WID);
+ }
+
+ return(0);
+}
+
+
+/****************************************************************************/
+/* Perform 32 bit based CRC calculation */
+/****************************************************************************/
+/* */
+/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */
+/* Ross N. Williams */
+/* http://www.rocksoft.com */
+/* */
+/* This performs a standard 32 bit crc on an array of arbitrary length */
+/* with an arbitrary initial value and passed generator polynomial */
+/* in the form of a crc table. */
+/* */
+/****************************************************************************/
+static u32 reflect (u32 data, u32 num)
+{
+ /* Reflects the lower num bits in 'data' around their center point. */
+ u32 i;
+ u32 j = 1;
+ u32 result = 0;
+
+ for (i=(u32)1<<(num-1); i; i>>=1) {
+ if (data & i) result|=j;
+ j <<= 1;
+ }
+ return(result);
+}
+
+
+/**
+ * byte_swap
+ */
+static u32 byte_swap (u32 data, u32 num)
+{
+ u32 i;
+ u32 result = 0;
+
+ if (num%16) {
+ dprintk("\nbyte_swap: ERROR: num is not an even number of bytes\n");
+ /* ASSERT(0); */
+ }
+
+ for (i = 0; i < num; i += 8) {
+ result |= (0xFF & (data >> i)) << (num-8-i);
+ }
+
+ return(result);
+}
+
+
+/**
+ * nes_crc32 -
+ * This is a reflected table algorithm. ReflectIn basically
+ * means to reflect each incomming byte of the data. But to make
+ * things more complicated, we can instead reflect the initial
+ * value, the final crc, and shift data to the right using a
+ * reflected pCRCTable. CRC is FUN!!
+ */
+u32 nes_crc32 ( u32 reverse,
+ u32 initialValue,
+ u32 finalXOR,
+ u32 messageLength,
+ u8 *pMessage,
+ u32 order,
+ u32 reflectIn,
+ u32 reflectOut)
+
+{
+ u8 *pBlockAddr = pMessage;
+ u32 mlen = messageLength;
+ u32 crc;
+
+ if (0 == nesCRCInitialized) {
+ nes_crc_table_gen( &nesCRCTable[0], CRC32C_POLY, ORDER, REFIN);
+ nesCRCInitialized = 1;
+ }
+
+ crc = (reflectIn) ? reflect(initialValue,order): initialValue;
+
+ while (mlen--) {
+ /* printf("byte = %x, index = %u, crctable[index] = %x\n",
+ *pBlockAddr, (crc & 0xffL) ^ *pBlockAddr,
+ nesCRCTable[(crc & 0xffL) ^ *pBlockAddr]);
+ */
+ if (reflectIn) {
+ crc = nesCRCTable[(crc & 0xffL ) ^ *pBlockAddr++] ^ (crc >> 8);
+ } else {
+ crc = nesCRCTable[((crc>>24) ^ *pBlockAddr++) & 0xFFL] ^ (crc << 8);
+ }
+ }
+
+ /* if reflectOut and reflectIn are both set, we don't */
+ /* do anything since reflecting twice effectively does nothing. */
+ crc = ((reflectIn)^(reflectOut)) ? reflect(crc,order): crc;
+
+ crc = crc^finalXOR;
+
+ /* We don't really use this, but it is here for completeness */
+ crc = (reverse) ? byte_swap(crc,32): crc;
+
+ return (crc);
+}
+
^ permalink raw reply
* [PATCH 2.6.24]S2io: Enhance device error/alarm handling
From: Ramkrishna Vepa @ 2007-08-08 3:15 UTC (permalink / raw)
To: netdev; +Cc: jeff, support
- Added support to poll for entire set of device errors and alarms.
- Optimized interrupt routine fast path.
- Removed the unused variable, intr_type, in device private structure.
Signed-off-by: Santosh Rastapur <santosh.rastapur@neterion.com>
Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com>
---
diff -Nurp 2.0.26.1/drivers/net/s2io.c 2.0.26.2/drivers/net/s2io.c
--- 2.0.26.1/drivers/net/s2io.c 2007-08-06 15:24:43.000000000 -0700
+++ 2.0.26.2/drivers/net/s2io.c 2007-08-06 15:22:29.000000000 -0700
@@ -84,7 +84,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.1"
+#define DRV_VERSION "2.0.26.2"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -263,7 +263,14 @@ static char ethtool_driver_stats_keys[][
{"serious_err_cnt"},
{"soft_reset_cnt"},
{"fifo_full_cnt"},
- {"ring_full_cnt"},
+ {"ring_0_full_cnt"},
+ {"ring_1_full_cnt"},
+ {"ring_2_full_cnt"},
+ {"ring_3_full_cnt"},
+ {"ring_4_full_cnt"},
+ {"ring_5_full_cnt"},
+ {"ring_6_full_cnt"},
+ {"ring_7_full_cnt"},
("alarm_transceiver_temp_high"),
("alarm_transceiver_temp_low"),
("alarm_laser_bias_current_high"),
@@ -303,7 +310,24 @@ static char ethtool_driver_stats_keys[][
("rx_tcode_fcs_err_cnt"),
("rx_tcode_buf_size_err_cnt"),
("rx_tcode_rxd_corrupt_cnt"),
- ("rx_tcode_unkn_err_cnt")
+ ("rx_tcode_unkn_err_cnt"),
+ {"tda_err_cnt"},
+ {"pfc_err_cnt"},
+ {"pcc_err_cnt"},
+ {"tti_err_cnt"},
+ {"tpa_err_cnt"},
+ {"sm_err_cnt"},
+ {"lso_err_cnt"},
+ {"mac_tmac_err_cnt"},
+ {"mac_rmac_err_cnt"},
+ {"xgxs_txgxs_err_cnt"},
+ {"xgxs_rxgxs_err_cnt"},
+ {"rc_err_cnt"},
+ {"prc_pcix_err_cnt"},
+ {"rpa_err_cnt"},
+ {"rda_err_cnt"},
+ {"rti_err_cnt"},
+ {"mc_err_cnt"}
};
#define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
@@ -802,7 +826,7 @@ static void free_shared_mem(struct s2io_
if (!nic)
return;
-
+
dev = nic->dev;
mac_control = &nic->mac_control;
@@ -892,7 +916,7 @@ static void free_shared_mem(struct s2io_
k++;
}
kfree(mac_control->rings[i].ba[j]);
- nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) *
+ nic->mac_control.stats_info->sw_stat.mem_freed += (sizeof(struct buffAdd) *
(rxd_count[nic->rxd_mode] + 1));
}
kfree(mac_control->rings[i].ba);
@@ -1456,7 +1480,7 @@ static int init_nic(struct s2io_nic *nic
&bar0->rts_frm_len_n[i]);
}
}
-
+
/* Disable differentiated services steering logic */
for (i = 0; i < 64; i++) {
if (rts_ds_steer(nic, i, 0) == FAILURE) {
@@ -1586,7 +1610,7 @@ static int init_nic(struct s2io_nic *nic
val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
RTI_DATA2_MEM_RX_UFC_B(0x2) ;
- if (nic->intr_type == MSI_X)
+ if (nic->config.intr_type == MSI_X)
val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
RTI_DATA2_MEM_RX_UFC_D(0x40));
else
@@ -1724,7 +1748,7 @@ static int init_nic(struct s2io_nic *nic
static int s2io_link_fault_indication(struct s2io_nic *nic)
{
- if (nic->intr_type != INTA)
+ if (nic->config.intr_type != INTA)
return MAC_RMAC_ERR_TIMER;
if (nic->device_type == XFRAME_II_DEVICE)
return LINK_UP_DOWN_INTERRUPT;
@@ -1732,6 +1756,362 @@ static int s2io_link_fault_indication(st
return MAC_RMAC_ERR_TIMER;
}
+
+void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
+{
+ struct XENA_dev_config __iomem *bar0 = nic->bar0;
+ register u64 val64 = 0, temp64 = 0, gen_int_mask = 0;
+
+ if (mask & TX_DMA_INTR) {
+ gen_int_mask |= TXDMA_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+
+ val64 = TXDMA_TDA_INT|TXDMA_PFC_INT|TXDMA_PCC_INT
+ |TXDMA_TTI_INT|TXDMA_LSO_INT|TXDMA_TPA_INT
+ |TXDMA_SM_INT;
+ temp64 = readq(&bar0->txdma_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->txdma_int_mask);
+
+ val64 = PFC_ECC_DB_ERR|PFC_SM_ERR_ALARM|PFC_MISC_0_ERR
+ |PFC_MISC_1_ERR|PFC_PCIX_ERR|PFC_ECC_SG_ERR;
+ temp64 = readq(&bar0->pfc_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->pfc_err_mask);
+
+ val64 = TDA_Fn_ECC_DB_ERR|TDA_SM0_ERR_ALARM
+ |TDA_SM1_ERR_ALARM|TDA_Fn_ECC_SG_ERR|TDA_PCIX_ERR;
+ temp64 = readq(&bar0->tda_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->tda_err_mask);
+
+ val64 = PCC_FB_ECC_DB_ERR|PCC_TXB_ECC_DB_ERR
+ |PCC_SM_ERR_ALARM|PCC_WR_ERR_ALARM|PCC_N_SERR
+ |PCC_6_COF_OV_ERR|PCC_7_COF_OV_ERR
+ |PCC_6_LSO_OV_ERR|PCC_7_LSO_OV_ERR
+ |PCC_FB_ECC_SG_ERR|PCC_TXB_ECC_SG_ERR;
+ temp64 = readq(&bar0->pcc_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->pcc_err_mask);
+
+ val64 = TTI_SM_ERR_ALARM|TTI_ECC_SG_ERR|TTI_ECC_DB_ERR;
+ temp64 = readq(&bar0->tti_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->tti_err_mask);
+
+
+ val64 = LSO6_ABORT|LSO7_ABORT|LSO6_SM_ERR_ALARM
+ |LSO7_SM_ERR_ALARM|LSO6_SEND_OFLOW|LSO7_SEND_OFLOW;
+ temp64 = readq(&bar0->lso_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->lso_err_mask);
+
+ val64 = TPA_SM_ERR_ALARM|TPA_TX_FRM_DROP;
+ temp64 = readq(&bar0->tpa_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->tpa_err_mask);
+
+ val64 = SM_SM_ERR_ALARM;
+ temp64 = readq(&bar0->sm_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->sm_err_mask);
+ }
+ else {
+ val64 = TXDMA_TDA_INT|TXDMA_PFC_INT|TXDMA_PCC_INT
+ |TXDMA_TTI_INT|TXDMA_LSO_INT|TXDMA_TPA_INT
+ |TXDMA_SM_INT;
+ temp64 = readq(&bar0->txdma_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->txdma_int_mask);
+
+ val64 = PFC_ECC_DB_ERR|PFC_SM_ERR_ALARM|PFC_MISC_0_ERR
+ |PFC_MISC_1_ERR|PFC_PCIX_ERR|PFC_ECC_SG_ERR;
+ temp64 = readq(&bar0->pfc_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->pfc_err_mask);
+
+ val64 = TDA_Fn_ECC_DB_ERR|TDA_SM0_ERR_ALARM
+ |TDA_Fn_ECC_SG_ERR|TDA_SM1_ERR_ALARM
+ |TDA_PCIX_ERR;
+ temp64 = readq(&bar0->tda_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->tda_err_mask);
+
+ val64 = PCC_FB_ECC_DB_ERR|PCC_TXB_ECC_DB_ERR
+ |PCC_SM_ERR_ALARM |PCC_WR_ERR_ALARM|PCC_N_SERR
+ |PCC_FB_ECC_SG_ERR|PCC_TXB_ECC_SG_ERR
+ |PCC_6_COF_OV_ERR|PCC_7_COF_OV_ERR
+ |PCC_6_LSO_OV_ERR|PCC_7_LSO_OV_ERR;
+ temp64 = readq(&bar0->pcc_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->pcc_err_mask);
+
+ val64 = TTI_SM_ERR_ALARM|TTI_ECC_SG_ERR|TTI_ECC_DB_ERR;
+ temp64 = readq(&bar0->tti_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->tti_err_mask);
+
+ val64 = LSO6_ABORT|LSO7_ABORT|LSO6_SM_ERR_ALARM
+ |LSO7_SM_ERR_ALARM|LSO6_SEND_OFLOW
+ |LSO7_SEND_OFLOW;
+ temp64 = readq(&bar0->lso_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->lso_err_mask);
+
+ val64 = TPA_SM_ERR_ALARM|TPA_TX_FRM_DROP;
+ temp64 = readq(&bar0->tpa_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->tpa_err_mask);
+
+ val64 = SM_SM_ERR_ALARM;
+ temp64 = readq(&bar0->sm_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->sm_err_mask);
+ }
+ }
+
+ if (mask & TX_MAC_INTR) {
+ gen_int_mask |= TXMAC_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = MAC_INT_STATUS_TMAC_INT;
+ temp64 = readq(&bar0->mac_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mac_int_mask);
+
+ val64 = TMAC_TX_BUF_OVRN|TMAC_TX_SM_ERR|TMAC_ECC_SG_ERR|
+ TMAC_ECC_DB_ERR|TMAC_DESC_ECC_SG_ERR|TMAC_DESC_ECC_DB_ERR;
+ temp64 = readq(&bar0->mac_tmac_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mac_tmac_err_mask);
+ }
+ else {
+ val64 = MAC_INT_STATUS_TMAC_INT;
+ temp64 = readq(&bar0->mac_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mac_int_mask);
+
+ val64 = TMAC_ECC_SG_ERR|TMAC_ECC_DB_ERR
+ |TMAC_TX_BUF_OVRN|TMAC_TX_SM_ERR
+ |TMAC_DESC_ECC_SG_ERR|TMAC_DESC_ECC_DB_ERR;
+ temp64 = readq(&bar0->mac_tmac_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mac_tmac_err_mask);
+ }
+ }
+
+ if (mask & TX_XGXS_INTR) {
+ gen_int_mask |= TXXGXS_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = XGXS_INT_STATUS_TXGXS;
+ temp64 = readq(&bar0->xgxs_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->xgxs_int_mask);
+
+ val64 = TXGXS_ESTORE_UFLOW|TXGXS_TX_SM_ERR|
+ TXGXS_ECC_SG_ERR|TXGXS_ECC_DB_ERR;
+ temp64 = readq(&bar0->xgxs_txgxs_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->xgxs_txgxs_err_mask);
+ }
+ else {
+ val64 = XGXS_INT_STATUS_TXGXS;
+ temp64 = readq(&bar0->mac_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mac_int_mask);
+
+ val64 = TXGXS_ECC_SG_ERR|TXGXS_ECC_DB_ERR
+ |TXGXS_ESTORE_UFLOW|TXGXS_TX_SM_ERR;
+ temp64 = readq(&bar0->xgxs_txgxs_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->xgxs_txgxs_err_mask);
+ }
+ }
+
+ if (mask & RX_DMA_INTR) {
+ gen_int_mask |= RXDMA_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = RXDMA_INT_RC_INT_M|RXDMA_INT_RPA_INT_M
+ |RXDMA_INT_RDA_INT_M|RXDMA_INT_RTI_INT_M;
+ temp64 = readq(&bar0->rxdma_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->rxdma_int_mask);
+
+ val64 = RC_PRCn_ECC_DB_ERR|RC_FTC_ECC_DB_ERR|
+ RC_PRCn_SM_ERR_ALARM|RC_FTC_SM_ERR_ALARM|
+ RC_PRCn_ECC_SG_ERR|RC_FTC_ECC_SG_ERR|
+ RC_RDA_FAIL_WR_Rn;
+ temp64 = readq(&bar0->rc_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->rc_err_mask);
+
+ val64 = PRC_PCI_AB_RD_Rn|PRC_PCI_AB_WR_Rn|
+ PRC_PCI_AB_F_WR_Rn|PRC_PCI_DP_RD_Rn|PRC_PCI_DP_WR_Rn|
+ PRC_PCI_DP_F_WR_Rn;
+ temp64 = readq(&bar0->prc_pcix_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->prc_pcix_err_mask);
+
+ val64 = RPA_SM_ERR_ALARM|RPA_CREDIT_ERR|
+ RPA_ECC_SG_ERR|RPA_ECC_DB_ERR;
+ temp64 = readq(&bar0->rpa_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->rpa_err_mask);
+
+ val64 = RDA_RXDn_ECC_DB_ERR|RDA_FRM_ECC_DB_N_AERR|
+ RDA_SM1_ERR_ALARM|RDA_SM0_ERR_ALARM|
+ RDA_RXD_ECC_DB_SERR|RDA_RXDn_ECC_SG_ERR|RDA_FRM_ECC_SG_ERR|
+ RDA_MISC_ERR|RDA_PCIX_ERR;
+ temp64 = readq(&bar0->rda_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->rda_err_mask);
+
+ val64 = RTI_SM_ERR_ALARM|RTI_ECC_SG_ERR|RTI_ECC_DB_ERR;
+ temp64 = readq(&bar0->rti_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->rti_err_mask);
+ }
+ else {
+ val64 = RXDMA_INT_RC_INT_M|RXDMA_INT_RPA_INT_M
+ |RXDMA_INT_RDA_INT_M|RXDMA_INT_RTI_INT_M;
+ temp64 = readq(&bar0->rxdma_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->rxdma_int_mask);
+
+ val64 = RC_PRCn_ECC_SG_ERR|RC_PRCn_ECC_DB_ERR
+ |RC_FTC_ECC_SG_ERR|RC_FTC_ECC_DB_ERR
+ |RC_PRCn_SM_ERR_ALARM|RC_FTC_SM_ERR_ALARM
+ |RC_RDA_FAIL_WR_Rn;
+ temp64 = readq(&bar0->rc_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->rc_err_mask);
+
+ val64 = PRC_PCI_AB_RD_Rn|PRC_PCI_DP_RD_Rn
+ |PRC_PCI_AB_WR_Rn|PRC_PCI_DP_WR_Rn
+ |PRC_PCI_AB_F_WR_Rn|PRC_PCI_DP_F_WR_Rn;
+ temp64 = readq(&bar0->prc_pcix_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->prc_pcix_err_mask);
+
+ val64 = RPA_ECC_SG_ERR|RPA_ECC_DB_ERR
+ |RPA_FLUSH_REQUEST|RPA_SM_ERR_ALARM
+ |RPA_CREDIT_ERR;
+ temp64 = readq(&bar0->rpa_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->rpa_err_mask);
+
+ val64 = RDA_RXDn_ECC_SG_ERR|RDA_RXDn_ECC_DB_ERR
+ |RDA_FRM_ECC_SG_ERR|RDA_FRM_ECC_DB_N_AERR
+ |RDA_SM1_ERR_ALARM|RDA_SM0_ERR_ALARM
+ |RDA_MISC_ERR|RDA_PCIX_ERR|RDA_RXD_ECC_DB_SERR;
+ temp64 = readq(&bar0->rda_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->rda_err_mask);
+
+ val64 = RTI_ECC_SG_ERR|RTI_ECC_DB_ERR|RTI_SM_ERR_ALARM;
+ temp64 = readq(&bar0->rti_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->rti_err_mask);
+ }
+ }
+
+ if (mask & RX_MAC_INTR) {
+ gen_int_mask |= RXMAC_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = MAC_INT_STATUS_RMAC_INT;
+ temp64 = readq(&bar0->mac_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mac_int_mask);
+
+ val64 = RMAC_RX_BUFF_OVRN|RMAC_RX_SM_ERR|
+ RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
+ RMAC_DOUBLE_ECC_ERR|RMAC_LINK_STATE_CHANGE_INT;
+ temp64 = readq(&bar0->mac_rmac_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mac_rmac_err_mask);
+ }
+ else {
+ val64 = MAC_INT_STATUS_RMAC_INT;
+ temp64 = readq(&bar0->mac_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mac_int_mask);
+
+ val64 = RMAC_RX_BUFF_OVRN|RMAC_FRM_RCVD_INT
+ |RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR
+ |RMAC_DOUBLE_ECC_ERR|RMAC_LINK_STATE_CHANGE_INT
+ |RMAC_RX_SM_ERR;
+ temp64 = readq(&bar0->mac_rmac_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mac_rmac_err_mask);
+ }
+ }
+
+ if (mask & RX_XGXS_INTR)
+ {
+ gen_int_mask |= RXXGXS_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = XGXS_INT_STATUS_RXGXS;
+ temp64 = readq(&bar0->xgxs_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->xgxs_int_mask);
+
+ val64 = RXGXS_ESTORE_OFLOW|RXGXS_RX_SM_ERR;
+ temp64 = readq(&bar0->xgxs_rxgxs_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->xgxs_rxgxs_err_mask);
+ }
+ else {
+ val64 = XGXS_INT_STATUS_RXGXS;
+ temp64 = readq(&bar0->xgxs_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->xgxs_int_mask);
+
+ val64 = RXGXS_ESTORE_OFLOW|RXGXS_RX_SM_ERR;
+ temp64 = readq(&bar0->xgxs_rxgxs_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->xgxs_rxgxs_err_mask);
+ }
+ }
+
+ if (mask & MC_INTR) {
+ gen_int_mask |= MC_INT_M;
+
+ if (flag == ENABLE_INTRS) {
+ val64 = MC_INT_MASK_MC_INT;
+ temp64 = readq(&bar0->mc_int_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mc_int_mask);
+
+ val64 = MC_ERR_REG_SM_ERR|MC_ERR_REG_ECC_ALL_SNG|
+ MC_ERR_REG_ECC_ALL_DBL;
+ temp64 = readq(&bar0->mc_err_mask);
+ temp64 &= ~((u64) val64);
+ writeq(temp64, &bar0->mc_err_mask);
+ }
+ else {
+ val64 = MC_INT_MASK_MC_INT;
+ temp64 = readq(&bar0->mc_int_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mc_int_mask);
+
+ val64 = MC_ERR_REG_ECC_ALL_SNG|MC_ERR_REG_ECC_ALL_DBL
+ |MC_ERR_REG_SM_ERR|PLL_LOCK_N;
+ temp64 = readq(&bar0->mc_err_mask);
+ temp64 |= ((u64) val64);
+ writeq(temp64, &bar0->mc_err_mask);
+ }
+ }
+ nic->general_int_mask = gen_int_mask;
+
+ /* Remove this line when alarm interrupts are enabled */
+ nic->general_int_mask = 0;
+}
+
/**
* en_dis_able_nic_intrs - Enable or Disable the interrupts
* @nic: device private variable,
@@ -1742,21 +2122,19 @@ static int s2io_link_fault_indication(st
* enable/disable any Intr block.
* Return Value: NONE.
*/
-
static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, temp64 = 0;
+ register u64 temp64 = 0, intr_mask = 0;
+
+ intr_mask = nic->general_int_mask;
/* Top level interrupt classification */
/* PIC Interrupts */
- if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
+ if (mask & TX_PIC_INTR) {
/* Enable PIC Intrs in the general intr mask register */
- val64 = TXPIC_INT_M;
+ intr_mask |= TXPIC_INT_M ;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* If Hercules adapter enable GPIO otherwise
* disable all PCIX, Flash, MDIO, IIC and GPIO
@@ -1771,58 +2149,21 @@ static void en_dis_able_nic_intrs(struct
temp64 = readq(&bar0->gpio_int_mask);
temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
writeq(temp64, &bar0->gpio_int_mask);
- } else {
+ } else
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- }
- /*
- * No MSI Support is available presently, so TTI and
- * RTI interrupts are also disabled.
- */
} else if (flag == DISABLE_INTRS) {
/*
* Disable PIC Intrs in the general
* intr mask register
*/
writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
- }
- }
-
- /* MAC Interrupts */
- /* Enabling/Disabling MAC interrupts */
- if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
- val64 = TXMAC_INT_M | RXMAC_INT_M;
- if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
- /*
- * All MAC block error interrupts are disabled for now
- * TODO
- */
- } else if (flag == DISABLE_INTRS) {
- /*
- * Disable MAC Intrs in the general intr mask register
- */
- writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
- writeq(DISABLE_ALL_INTRS,
- &bar0->mac_rmac_err_mask);
-
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Tx traffic interrupts */
if (mask & TX_TRAFFIC_INTR) {
- val64 = TXTRAFFIC_INT_M;
+ intr_mask |= TXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/*
* Enable all the Tx side interrupts
* writing 0 Enables all 64 TX interrupt levels
@@ -1834,19 +2175,13 @@ static void en_dis_able_nic_intrs(struct
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
/* Rx traffic interrupts */
if (mask & RX_TRAFFIC_INTR) {
- val64 = RXTRAFFIC_INT_M;
+ intr_mask |= RXTRAFFIC_INT_M;
if (flag == ENABLE_INTRS) {
- temp64 = readq(&bar0->general_int_mask);
- temp64 &= ~((u64) val64);
- writeq(temp64, &bar0->general_int_mask);
/* writing 0 Enables all 8 RX interrupt levels */
writeq(0x0, &bar0->rx_traffic_mask);
} else if (flag == DISABLE_INTRS) {
@@ -1855,11 +2190,17 @@ static void en_dis_able_nic_intrs(struct
* register.
*/
writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
- temp64 = readq(&bar0->general_int_mask);
- val64 |= temp64;
- writeq(val64, &bar0->general_int_mask);
}
}
+
+ temp64 = readq(&bar0->general_int_mask);
+ if (flag == ENABLE_INTRS)
+ temp64 &= ~((u64) intr_mask);
+ else
+ temp64 = DISABLE_ALL_INTRS;
+ writeq(temp64, &bar0->general_int_mask);
+
+ nic->general_int_mask = readq(&bar0->general_int_mask);
}
/**
@@ -1872,7 +2213,7 @@ static int verify_pcc_quiescent(struct s
int ret = 0, herc;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = readq(&bar0->adapter_status);
-
+
herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
@@ -2063,14 +2404,6 @@ static int start_nic(struct s2io_nic *ni
writeq(val64, &bar0->adapter_control);
/*
- * Clearing any possible Link state change interrupts that
- * could have popped up just before Enabling the card.
- */
- val64 = readq(&bar0->mac_rmac_err_reg);
- if (val64)
- writeq(val64, &bar0->mac_rmac_err_reg);
-
- /*
* Verify if the device is ready to be enabled, if so enable
* it.
*/
@@ -2223,9 +2556,9 @@ static void stop_nic(struct s2io_nic *ni
config = &nic->config;
/* Disable all interrupts */
+ en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS);
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
/* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
@@ -2589,6 +2922,12 @@ static int s2io_poll(struct net_device *
int i;
atomic_inc(&nic->isr_cnt);
+
+ if (unlikely(atomic_read(&nic->card_state) == CARD_DOWN)) {
+ atomic_dec(&nic->isr_cnt);
+ return IRQ_NONE;
+ }
+
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2724,13 +3063,6 @@ static void rx_intr_handler(struct ring_
struct RxD3* rxdp3;
spin_lock(&nic->rx_lock);
- if (atomic_read(&nic->card_state) == CARD_DOWN) {
- DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
- __FUNCTION__, dev->name);
- spin_unlock(&nic->rx_lock);
- return;
- }
-
get_info = ring_data->rx_curr_get_info;
get_block = get_info.block_index;
memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
@@ -3164,135 +3496,6 @@ static void s2io_updt_xpak_counter(struc
}
/**
- * alarm_intr_handler - Alarm Interrrupt handler
- * @nic: device private variable
- * Description: If the interrupt was neither because of Rx packet or Tx
- * complete, this function is called. If the interrupt was to indicate
- * a loss of link, the OSM link status handler is invoked for any other
- * alarm interrupt the block that raised the interrupt is displayed
- * and a H/W reset is issued.
- * Return Value:
- * NONE
-*/
-
-static void alarm_intr_handler(struct s2io_nic *nic)
-{
- struct net_device *dev = (struct net_device *) nic->dev;
- struct XENA_dev_config __iomem *bar0 = nic->bar0;
- register u64 val64 = 0, err_reg = 0;
- u64 cnt;
- int i;
- if (atomic_read(&nic->card_state) == CARD_DOWN)
- return;
- if (pci_channel_offline(nic->pdev))
- return;
- nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
- /* Handling the XPAK counters update */
- if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
- /* waiting for an hour */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
- } else {
- s2io_updt_xpak_counter(dev);
- /* reset the count to zero */
- nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
- }
-
- /* Handling link status change error Intr */
- if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
- err_reg = readq(&bar0->mac_rmac_err_reg);
- writeq(err_reg, &bar0->mac_rmac_err_reg);
- if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
- schedule_work(&nic->set_link_task);
- }
- }
-
- /* Handling Ecc errors */
- val64 = readq(&bar0->mc_err_reg);
- writeq(val64, &bar0->mc_err_reg);
- if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
- if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
- nic->mac_control.stats_info->sw_stat.
- double_ecc_errs++;
- DBG_PRINT(INIT_DBG, "%s: Device indicates ",
- dev->name);
- DBG_PRINT(INIT_DBG, "double ECC error!!\n");
- if (nic->device_type != XFRAME_II_DEVICE) {
- /* Reset XframeI only if critical error */
- if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
- MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.
- soft_reset_cnt++;
- }
- }
- } else {
- nic->mac_control.stats_info->sw_stat.
- single_ecc_errs++;
- }
- }
-
- /* In case of a serious error, the device will be Reset. */
- val64 = readq(&bar0->serr_source);
- if (val64 & SERR_SOURCE_ANY) {
- nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
- DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
- DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
- (unsigned long long)val64);
- netif_stop_queue(dev);
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
-
- /*
- * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
- * Error occurs, the adapter will be recycled by disabling the
- * adapter enable bit and enabling it again after the device
- * becomes Quiescent.
- */
- val64 = readq(&bar0->pcc_err_reg);
- writeq(val64, &bar0->pcc_err_reg);
- if (val64 & PCC_FB_ECC_DB_ERR) {
- u64 ac = readq(&bar0->adapter_control);
- ac &= ~(ADAPTER_CNTL_EN);
- writeq(ac, &bar0->adapter_control);
- ac = readq(&bar0->adapter_control);
- schedule_work(&nic->set_link_task);
- }
- /* Check for data parity error */
- val64 = readq(&bar0->pic_int_status);
- if (val64 & PIC_INT_GPIO) {
- val64 = readq(&bar0->gpio_int_reg);
- if (val64 & GPIO_INT_REG_DP_ERR_INT) {
- nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
- schedule_work(&nic->rst_timer_task);
- nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
- }
- }
-
- /* Check for ring full counter */
- if (nic->device_type & XFRAME_II_DEVICE) {
- val64 = readq(&bar0->ring_bump_counter1);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
-
- val64 = readq(&bar0->ring_bump_counter2);
- for (i=0; i<4; i++) {
- cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
- cnt >>= 64 - ((i+1)*16);
- nic->mac_control.stats_info->sw_stat.ring_full_cnt
- += cnt;
- }
- }
-
- /* Other type of interrupts are not being handled now, TODO */
-}
-
-/**
* wait_for_cmd_complete - waits for a command to complete.
* @sp : private member of the device structure, which is a pointer to the
* s2io_nic structure.
@@ -3426,7 +3629,7 @@ static void s2io_reset(struct s2io_nic *
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
-
+
up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
@@ -3565,7 +3768,7 @@ static int s2io_set_swapper(struct s2io_
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#else
@@ -3588,7 +3791,7 @@ static int s2io_set_swapper(struct s2io_
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
- if (sp->intr_type == INTA)
+ if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl);
#endif
@@ -3862,7 +4065,7 @@ static int s2io_open(struct net_device *
netif_carrier_off(dev);
sp->last_link_state = 0;
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
int ret = s2io_enable_msi_x(sp);
if (!ret) {
@@ -3894,12 +4097,12 @@ static int s2io_open(struct net_device *
DBG_PRINT(ERR_DBG,
"%s: MSI-X requested but failed to enable\n",
dev->name);
- sp->intr_type = INTA;
+ sp->config.intr_type = INTA;
}
}
/* NAPI doesn't work well with MSI(X) */
- if (sp->intr_type != INTA) {
+ if (sp->config.intr_type != INTA) {
if(sp->config.napi)
sp->config.napi = 0;
}
@@ -3923,7 +4126,7 @@ static int s2io_open(struct net_device *
return 0;
hw_init_failed:
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
if (sp->entries) {
kfree(sp->entries);
sp->mac_control.stats_info->sw_stat.mem_freed
@@ -3999,7 +4202,7 @@ static int s2io_xmit(struct sk_buff *skb
DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
dev_kfree_skb_any(skb);
return 0;
-}
+ }
spin_lock_irqsave(&sp->tx_lock, flags);
if (atomic_read(&sp->card_state) == CARD_DOWN) {
@@ -4154,9 +4357,11 @@ static void
s2io_alarm_handle(unsigned long data)
{
struct s2io_nic *sp = (struct s2io_nic *)data;
+ struct net_device *dev = sp->dev;
- alarm_intr_handler(sp);
- mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
+ s2io_handle_errors(dev);
+
+ mod_timer(&sp->alarm_timer, jiffies + HZ/2);
}
static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
@@ -4195,6 +4400,11 @@ static irqreturn_t s2io_msix_ring_handle
atomic_inc(&sp->isr_cnt);
+ if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)){
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
+ }
+
rx_intr_handler(ring);
s2io_chk_rx_buffers(sp, ring->ring_no);
@@ -4208,6 +4418,12 @@ static irqreturn_t s2io_msix_fifo_handle
struct s2io_nic *sp = fifo->nic;
atomic_inc(&sp->isr_cnt);
+
+ if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)){
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
+ }
+
tx_intr_handler(fifo);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
@@ -4273,6 +4489,383 @@ static void s2io_txpic_intr_handle(struc
val64 = readq(&bar0->gpio_int_mask);
}
+/*
+ * Checking for reset and SERR bits in the error registers
+ */
+static void s2io_handle_errors(void * dev_id)
+{
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct s2io_nic *sp = dev->priv;
+ struct XENA_dev_config __iomem *bar0 = sp->bar0;
+ u64 temp64 = 0,val64=0;
+ int i = 0;
+
+ struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat;
+ struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat;
+
+ if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN))
+ return;
+
+ if (pci_channel_offline(sp->pdev))
+ return;
+
+ memset(&sw_stat->ring_full_cnt, 0,
+ sizeof(sw_stat->ring_full_cnt));
+
+ /* Handling the XPAK counters update */
+ if(stats->xpak_timer_count < 72000) {
+ /* waiting for an hour */
+ stats->xpak_timer_count++;
+ } else {
+ s2io_updt_xpak_counter(dev);
+ /* reset the count to zero */
+ stats->xpak_timer_count = 0;
+ }
+
+ /* Handling link status change error Intr */
+ if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
+ val64 = readq(&bar0->mac_rmac_err_reg);
+ writeq(val64, &bar0->mac_rmac_err_reg);
+ if (val64 & RMAC_LINK_STATE_CHANGE_INT)
+ schedule_work(&sp->set_link_task);
+ }
+
+ /* In case of a serious error, the device will be Reset. */
+ val64 = readq(&bar0->serr_source);
+ if (val64 & SERR_SOURCE_ANY) {
+ sw_stat->serious_err_cnt++;
+ goto reset;
+ }
+
+ /* Check for data parity error */
+ val64 = readq(&bar0->gpio_int_reg);
+ if (val64 & GPIO_INT_REG_DP_ERR_INT) {
+ sw_stat->parity_err_cnt++;
+ goto reset;
+ }
+
+ /* Check for ring full counter */
+ if (sp->device_type == XFRAME_II_DEVICE) {
+ val64 = readq(&bar0->ring_bump_counter1);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i] += temp64;
+ }
+
+ val64 = readq(&bar0->ring_bump_counter2);
+ for (i=0; i<4; i++) {
+ temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+ temp64 >>= 64 - ((i+1)*16);
+ sw_stat->ring_full_cnt[i+4] += temp64;
+ }
+ }
+
+ val64 = readq(&bar0->txdma_int_status);
+ /*check for pfc_err*/
+ if (val64 & TXDMA_PFC_INT) {
+ val64 = readq(&bar0->pfc_err_reg);
+ temp64 = PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM
+ | PFC_MISC_0_ERR | PFC_MISC_1_ERR
+ | PFC_PCIX_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->pfc_err_reg);
+ sw_stat->pfc_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = PFC_ECC_SG_ERR;
+ if (val64 & temp64) {
+ sw_stat->pfc_err_cnt++;
+ writeq(val64, &bar0->pfc_err_reg);
+ }
+ }
+
+ /*check for tda_err*/
+ if (val64 & TXDMA_TDA_INT) {
+ val64 = readq(&bar0->tda_err_reg);
+ temp64 = TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM
+ | TDA_SM1_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->tda_err_reg);
+ sw_stat->tda_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR;
+ if (val64 & temp64) {
+ sw_stat->tda_err_cnt++;
+ writeq(val64, &bar0->tda_err_reg);
+ }
+ }
+ /*check for pcc_err*/
+ if (val64 & TXDMA_PCC_INT) {
+ val64 = readq(&bar0->pcc_err_reg);
+ temp64 = PCC_TXB_ECC_DB_ERR
+ | PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM
+ | PCC_N_SERR | PCC_6_COF_OV_ERR
+ | PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR
+ | PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR
+ | PCC_TXB_ECC_DB_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->pcc_err_reg);
+ sw_stat->pcc_err_cnt++;
+ goto reset;
+ }
+
+ if (val64 & (PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR)) {
+ sw_stat->pcc_err_cnt++;
+ writeq(val64, &bar0->pcc_err_reg);
+ }
+ }
+
+ /*check for tti_err*/
+ if (val64 & TXDMA_TTI_INT) {
+ val64 = readq(&bar0->tti_err_reg);
+ temp64 = TTI_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->tti_err_reg);
+ sw_stat->tti_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = TTI_ECC_SG_ERR | TTI_ECC_DB_ERR;
+ if (val64 & temp64) {
+ sw_stat->tti_err_cnt++;
+ writeq(val64, &bar0->tti_err_reg);
+ }
+ }
+
+ /*check for lso_err*/
+ if (val64 & TXDMA_LSO_INT) {
+ val64 = readq(&bar0->lso_err_reg);
+ temp64 = LSO6_ABORT | LSO7_ABORT
+ | LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->lso_err_reg);
+ sw_stat->lso_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = LSO6_SEND_OFLOW | LSO7_SEND_OFLOW;
+ if (val64 & temp64) {
+ sw_stat->lso_err_cnt++;
+ writeq(val64, &bar0->lso_err_reg);
+ }
+ }
+
+ /*check for tpa_err*/
+ if (val64 & TXDMA_TPA_INT) {
+ val64 = readq(&bar0->tpa_err_reg);
+ temp64 = TPA_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->tpa_err_reg);
+ sw_stat->tpa_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = TPA_TX_FRM_DROP;
+ if (val64 & temp64) {
+ sw_stat->tpa_err_cnt++;
+ writeq(val64, &bar0->tpa_err_reg);
+ }
+ }
+
+ /*check for sm_err*/
+ if (val64 & TXDMA_SM_INT) {
+ val64 = readq(&bar0->sm_err_reg);
+ temp64 = SM_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->sm_err_reg);
+ sw_stat->sm_err_cnt++;
+ goto reset;
+ }
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_TMAC_INT) {
+ val64 = readq(&bar0->mac_tmac_err_reg);
+ temp64 = TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR;
+ if ( val64 & temp64) {
+ writeq(val64, &bar0->mac_tmac_err_reg);
+ sw_stat->mac_tmac_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR
+ | TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR;
+ if (val64 & temp64) {
+ sw_stat->mac_tmac_err_cnt++;
+ writeq(val64, &bar0->mac_tmac_err_reg);
+ }
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_TXGXS) {
+ val64 = readq(&bar0->xgxs_txgxs_err_reg);
+ temp64 = TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR;
+ if ( val64 & temp64) {
+ writeq(val64, &bar0->xgxs_txgxs_err_reg);
+ sw_stat->xgxs_txgxs_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR;
+ if (val64 & temp64) {
+ sw_stat->xgxs_txgxs_err_cnt++;
+ writeq(val64, &bar0->xgxs_txgxs_err_reg);
+ }
+ }
+
+ val64 = readq(&bar0->rxdma_int_status);
+ if (val64 & RXDMA_INT_RC_INT_M) {
+ val64 = readq(&bar0->rc_err_reg);
+ temp64 = RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR
+ | RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->rc_err_reg);
+ sw_stat->rc_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR
+ | RC_RDA_FAIL_WR_Rn;
+ if (val64 & temp64) {
+ sw_stat->rc_err_cnt++;
+ writeq(val64, &bar0->rc_err_reg);
+ }
+
+ val64 = readq(&bar0->prc_pcix_err_reg);
+ temp64 = PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn
+ | PRC_PCI_AB_F_WR_Rn;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->prc_pcix_err_reg);
+ sw_stat->prc_pcix_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn
+ | PRC_PCI_DP_F_WR_Rn;
+ if (val64 & temp64) {
+ sw_stat->prc_pcix_err_cnt++;
+ writeq(val64, &bar0->prc_pcix_err_reg);
+ }
+ }
+
+ if (val64 & RXDMA_INT_RPA_INT_M) {
+ val64 = readq(&bar0->rpa_err_reg);
+ temp64 = RPA_SM_ERR_ALARM | RPA_CREDIT_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->rpa_err_reg);
+ sw_stat->rpa_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = RPA_ECC_SG_ERR | RPA_ECC_DB_ERR;
+ if (val64 & temp64) {
+ sw_stat->rpa_err_cnt++;
+ writeq(val64, &bar0->rpa_err_reg);
+ }
+ }
+
+ if (val64 & RXDMA_INT_RDA_INT_M) {
+ val64 = readq(&bar0->rda_err_reg);
+ temp64 = RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR
+ | RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM
+ | RDA_RXD_ECC_DB_SERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->rda_err_reg);
+ sw_stat->rda_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR
+ | RDA_MISC_ERR | RDA_PCIX_ERR;
+ if (val64 & temp64) {
+ sw_stat->rda_err_cnt++;
+ writeq(val64, &bar0->rda_err_reg);
+ }
+ }
+
+ if (val64 & RXDMA_INT_RTI_INT_M) {
+ val64 = readq(&bar0->rti_err_reg);
+ temp64 = RTI_SM_ERR_ALARM;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->rti_err_reg);
+ sw_stat->rti_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = RTI_ECC_SG_ERR | RTI_ECC_DB_ERR;
+ if (val64 & temp64) {
+ sw_stat->rti_err_cnt++;
+ writeq(val64, &bar0->rti_err_reg);
+ }
+ }
+
+ val64 = readq(&bar0->mac_int_status);
+ if (val64 & MAC_INT_STATUS_RMAC_INT) {
+ val64 = readq(&bar0->mac_rmac_err_reg);
+ temp64 = RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->mac_rmac_err_reg);
+ sw_stat->mac_rmac_err_cnt++;
+ goto reset;
+ }
+
+ temp64 = RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
+ RMAC_DOUBLE_ECC_ERR;
+ if (val64 & temp64) {
+ sw_stat->mac_rmac_err_cnt++;
+ writeq(val64, &bar0->mac_rmac_err_reg);
+ }
+ }
+
+ val64 = readq(&bar0->xgxs_int_status);
+ if (val64 & XGXS_INT_STATUS_RXGXS) {
+ val64 = readq(&bar0->xgxs_rxgxs_err_reg);
+ temp64 = RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->xgxs_rxgxs_err_reg);
+ sw_stat->xgxs_rxgxs_err_cnt++;
+ goto reset;
+ }
+ }
+
+ val64 = readq(&bar0->mc_int_status);
+ if(val64 & MC_INT_STATUS_MC_INT) {
+ val64 = readq(&bar0->mc_err_reg);
+ temp64 = MC_ERR_REG_SM_ERR;
+ if ( val64 & temp64 ) {
+ writeq(val64, &bar0->mc_err_reg);
+ sw_stat->mc_err_cnt++;
+ goto reset;
+ }
+
+ /* Handling Ecc errors */
+ if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
+ writeq(val64, &bar0->mc_err_reg);
+ if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
+ sw_stat->double_ecc_errs++;
+ if (sp->device_type != XFRAME_II_DEVICE) {
+ /* Reset XframeI only if critical error */
+ if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+ MC_ERR_REG_MIRI_ECC_DB_ERR_1))
+ goto reset;
+ }
+ } else
+ sw_stat->single_ecc_errs++;
+ }
+ }
+ return;
+
+reset:
+ netif_stop_queue(dev);
+ schedule_work(&sp->rst_timer_task);
+ sw_stat->soft_reset_cnt++;
+ return;
+}
+
/**
* s2io_isr - ISR handler of the device .
* @irq: the irq of the device.
@@ -4301,6 +4894,12 @@ static irqreturn_t s2io_isr(int irq, voi
return IRQ_NONE;
atomic_inc(&sp->isr_cnt);
+
+ if (unlikely(atomic_read(&sp->card_state) == CARD_DOWN)) {
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_NONE;
+ }
+
mac_control = &sp->mac_control;
config = &sp->config;
@@ -4310,71 +4909,74 @@ static irqreturn_t s2io_isr(int irq, voi
* 1. Rx of packet.
* 2. Tx complete.
* 3. Link down.
- * 4. Error in any functional blocks of the NIC.
*/
reason = readq(&bar0->general_int_status);
- if (!reason) {
- /* The interrupt was not raised by us. */
- atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
- }
- else if (unlikely(reason == S2IO_MINUS_ONE) ) {
- /* Disable device and get out */
+ if ( unlikely(reason == S2IO_MINUS_ONE) ) {
+ /* Nothing much can be done. Get out */
atomic_dec(&sp->isr_cnt);
- return IRQ_NONE;
+ return IRQ_HANDLED;
}
- if (napi) {
- if (reason & GEN_INTR_RXTRAFFIC) {
- if ( likely ( netif_rx_schedule_prep(dev)) ) {
- __netif_rx_schedule(dev);
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ if (reason & (GEN_INTR_RXTRAFFIC |
+ GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC))
+ {
+ writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
+
+ if (config->napi) {
+ if (reason & GEN_INTR_RXTRAFFIC) {
+ if ( likely (netif_rx_schedule_prep(dev)) ) {
+ __netif_rx_schedule(dev);
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+ } else
+ writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
}
- else
+ } else {
+ /*
+ * rx_traffic_int reg is an R1 register, writing all 1's
+ * will ensure that the actual interrupt causing bit get's
+ * cleared and hence a read can be avoided.
+ */
+ if (reason & GEN_INTR_RXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+
+ for (i = 0; i < config->rx_ring_num; i++)
+ rx_intr_handler(&mac_control->rings[i]);
}
- } else {
+
/*
- * Rx handler is called by default, without checking for the
- * cause of interrupt.
- * rx_traffic_int reg is an R1 register, writing all 1's
+ * tx_traffic_int reg is an R1 register, writing all 1's
* will ensure that the actual interrupt causing bit get's
* cleared and hence a read can be avoided.
*/
- if (reason & GEN_INTR_RXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+ if (reason & GEN_INTR_TXTRAFFIC)
+ writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
- for (i = 0; i < config->rx_ring_num; i++) {
- rx_intr_handler(&mac_control->rings[i]);
- }
- }
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
- /*
- * tx_traffic_int reg is an R1 register, writing all 1's
- * will ensure that the actual interrupt causing bit get's
- * cleared and hence a read can be avoided.
- */
- if (reason & GEN_INTR_TXTRAFFIC)
- writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
+ if (reason & GEN_INTR_TXPIC)
+ s2io_txpic_intr_handle(sp);
- for (i = 0; i < config->tx_fifo_num; i++)
- tx_intr_handler(&mac_control->fifos[i]);
+ /*
+ * Reallocate the buffers from the interrupt handler itself.
+ */
+ if (!config->napi) {
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
+ }
+ writeq(sp->general_int_mask, &bar0->general_int_mask);
+ readl(&bar0->general_int_status);
- if (reason & GEN_INTR_TXPIC)
- s2io_txpic_intr_handle(sp);
- /*
- * If the Rx buffer count is below the panic threshold then
- * reallocate the buffers from the interrupt handler itself,
- * else schedule a tasklet to reallocate the buffers.
- */
- if (!napi) {
- for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
- }
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_HANDLED;
- writeq(0, &bar0->general_int_mask);
- readl(&bar0->general_int_status);
+ }
+ else if (!reason) {
+ /* The interrupt was not raised by us */
+ atomic_dec(&sp->isr_cnt);
+ return IRQ_NONE;
+ }
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
@@ -4403,7 +5005,7 @@ static void s2io_updt_stats(struct s2io_
if (cnt == 5)
break; /* Updt failed */
} while(1);
- }
+ }
}
/**
@@ -4900,7 +5502,7 @@ static void s2io_ethtool_gringparam(stru
ering->tx_max_pending = MAX_TX_DESC;
for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
tx_desc_count += sp->config.tx_cfg[i].fifo_len;
-
+
DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
ering->tx_pending = tx_desc_count;
rx_desc_count = 0;
@@ -5662,7 +6264,7 @@ static void s2io_get_ethtool_stats(struc
struct ethtool_stats *estats,
u64 * tmp_stats)
{
- int i = 0;
+ int i = 0, k = 0;
struct s2io_nic *sp = dev->priv;
struct stat_block *stat_info = sp->mac_control.stats_info;
@@ -5857,7 +6459,8 @@ static void s2io_get_ethtool_stats(struc
tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
- tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
+ for (k = 0; k < MAX_RX_RINGS; k++)
+ tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k];
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
@@ -5914,6 +6517,23 @@ static void s2io_get_ethtool_stats(struc
tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt;
+ tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt;
}
static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -6404,18 +7024,18 @@ static int s2io_add_isr(struct s2io_nic
struct net_device *dev = sp->dev;
int err = 0;
- if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
ret = s2io_enable_msi_x(sp);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
- sp->intr_type = INTA;
+ sp->config.intr_type = INTA;
}
/* Store the values of the MSIX table in the struct s2io_nic structure */
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */
- if (sp->intr_type == MSI_X) {
+ if (sp->config.intr_type == MSI_X) {
int i, msix_tx_cnt=0,msix_rx_cnt=0;
for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
@@ -6467,7 +7087,7 @@ static int s2io_add_isr(struct s2io_nic
printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
}
- if (sp->intr_type == INTA) {
+ if (sp->config.intr_type == INTA) {
err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
sp->name, dev);
if (err) {
@@ -6484,7 +7104,15 @@ static void s2io_rem_isr(struct s2io_nic
struct net_device *dev = sp->dev;
struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
- if (sp->intr_type == MSI_X) {
+ /* Waiting till all Interrupt handlers are complete */
+ do {
+ if (!atomic_read(&sp->isr_cnt))
+ break;
+ msleep(10);
+ cnt++;
+ } while(cnt < 5);
+
+ if (sp->config.intr_type == MSI_X) {
int i;
u16 msi_control;
@@ -6513,14 +7141,6 @@ static void s2io_rem_isr(struct s2io_nic
} else {
free_irq(sp->pdev->irq, dev);
}
- /* Waiting till all Interrupt handlers are complete */
- cnt = 0;
- do {
- msleep(10);
- if (!atomic_read(&sp->isr_cnt))
- break;
- cnt++;
- } while(cnt < 5);
}
static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
@@ -6657,7 +7277,7 @@ static int s2io_card_up(struct s2io_nic
/* Add interrupt service routine */
if (s2io_add_isr(sp) != 0) {
- if (sp->intr_type == MSI_X)
+ if (sp->config.intr_type == MSI_X)
s2io_rem_isr(sp);
s2io_reset(sp);
free_rx_buffers(sp);
@@ -6670,16 +7290,16 @@ static int s2io_card_up(struct s2io_nic
tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
/* Enable select interrupts */
- if (sp->intr_type != INTA)
+ en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
+
+ if (sp->config.intr_type != INTA)
en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
else {
interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ interruptible |= TX_PIC_INTR;
en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
}
-
atomic_set(&sp->card_state, CARD_UP);
return 0;
}
@@ -7051,19 +7671,12 @@ static int s2io_verify_parm(struct pci_d
if (*dev_intr_type != INTA)
napi = 0;
-#ifndef CONFIG_PCI_MSI
- if (*dev_intr_type != INTA) {
- DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
- "MSI/MSI-X. Defaulting to INTA\n");
- *dev_intr_type = INTA;
- }
-#else
if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
-#endif
+
if ((*dev_intr_type == MSI_X) &&
((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
@@ -7198,7 +7811,7 @@ s2io_init_nic(struct pci_dev *pdev, cons
if (rx_ring_mode == 2)
sp->rxd_mode = RXD_MODE_3B;
- sp->intr_type = dev_intr_type;
+ sp->config.intr_type = dev_intr_type;
if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
(pdev->device == PCI_DEVICE_ID_HERC_UNI))
@@ -7221,6 +7834,8 @@ s2io_init_nic(struct pci_dev *pdev, cons
mac_control = &sp->mac_control;
config = &sp->config;
+ config->napi = napi;
+
/* Tx side parameters. */
config->tx_fifo_num = tx_fifo_num;
for (i = 0; i < MAX_TX_FIFOS; i++) {
@@ -7478,7 +8093,7 @@ s2io_init_nic(struct pci_dev *pdev, cons
if (napi)
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
- switch(sp->intr_type) {
+ switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
break;
diff -Nurp 2.0.26.1/drivers/net/s2io.h 2.0.26.2/drivers/net/s2io.h
--- 2.0.26.1/drivers/net/s2io.h 2007-08-03 15:09:15.000000000 -0700
+++ 2.0.26.2/drivers/net/s2io.h 2007-08-03 17:45:06.000000000 -0700
@@ -91,7 +91,7 @@ struct swStat {
unsigned long long serious_err_cnt;
unsigned long long soft_reset_cnt;
unsigned long long fifo_full_cnt;
- unsigned long long ring_full_cnt;
+ unsigned long long ring_full_cnt[8];
/* LRO statistics */
unsigned long long clubbed_frms_cnt;
unsigned long long sending_both;
@@ -126,6 +126,25 @@ struct swStat {
unsigned long long rx_buf_size_err_cnt;
unsigned long long rx_rxd_corrupt_cnt;
unsigned long long rx_unkn_err_cnt;
+
+ /* Error/alarm statistics*/
+ unsigned long long tda_err_cnt;
+ unsigned long long pfc_err_cnt;
+ unsigned long long pcc_err_cnt;
+ unsigned long long tti_err_cnt;
+ unsigned long long lso_err_cnt;
+ unsigned long long tpa_err_cnt;
+ unsigned long long sm_err_cnt;
+ unsigned long long mac_tmac_err_cnt;
+ unsigned long long mac_rmac_err_cnt;
+ unsigned long long xgxs_txgxs_err_cnt;
+ unsigned long long xgxs_rxgxs_err_cnt;
+ unsigned long long rc_err_cnt;
+ unsigned long long prc_pcix_err_cnt;
+ unsigned long long rpa_err_cnt;
+ unsigned long long rda_err_cnt;
+ unsigned long long rti_err_cnt;
+ unsigned long long mc_err_cnt;
};
/* Xpak releated alarm and warnings */
@@ -886,12 +905,9 @@ struct s2io_nic {
u8 lro;
u16 lro_max_aggr_per_sess;
-#define INTA 0
-#define MSI_X 2
- u8 intr_type;
-
spinlock_t rx_lock;
atomic_t isr_cnt;
+ u64 general_int_mask;
u64 *ufo_in_band_v;
#define VPD_STRING_LEN 80
u8 product_name[VPD_STRING_LEN];
@@ -1016,7 +1032,7 @@ static void free_shared_mem(struct s2io_
static int init_nic(struct s2io_nic *nic);
static void rx_intr_handler(struct ring_info *ring_data);
static void tx_intr_handler(struct fifo_info *fifo_data);
-static void alarm_intr_handler(struct s2io_nic *sp);
+static void s2io_handle_errors(void * dev_id);
static int s2io_starter(void);
static void s2io_closer(void);
diff -Nurp 2.0.26.1/drivers/net/s2io-regs.h 2.0.26.2/drivers/net/s2io-regs.h
--- 2.0.26.1/drivers/net/s2io-regs.h 2007-08-03 15:09:16.000000000 -0700
+++ 2.0.26.2/drivers/net/s2io-regs.h 2007-08-03 15:10:41.000000000 -0700
@@ -325,33 +325,65 @@ struct XENA_dev_config {
#define TXDMA_TPA_INT BIT(5)
#define TXDMA_SM_INT BIT(6)
u64 pfc_err_reg;
+#define PFC_ECC_SG_ERR BIT(7)
+#define PFC_ECC_DB_ERR BIT(15)
+#define PFC_SM_ERR_ALARM BIT(23)
+#define PFC_MISC_0_ERR BIT(31)
+#define PFC_MISC_1_ERR BIT(32)
+#define PFC_PCIX_ERR BIT(39)
u64 pfc_err_mask;
u64 pfc_err_alarm;
u64 tda_err_reg;
+#define TDA_Fn_ECC_SG_ERR vBIT(0xff,0,8)
+#define TDA_Fn_ECC_DB_ERR vBIT(0xff,8,8)
+#define TDA_SM0_ERR_ALARM BIT(22)
+#define TDA_SM1_ERR_ALARM BIT(23)
+#define TDA_PCIX_ERR BIT(39)
u64 tda_err_mask;
u64 tda_err_alarm;
u64 pcc_err_reg;
-#define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8)
+#define PCC_FB_ECC_SG_ERR vBIT(0xFF,0,8)
+#define PCC_TXB_ECC_SG_ERR vBIT(0xFF,8,8)
+#define PCC_FB_ECC_DB_ERR vBIT(0xFF,16, 8)
+#define PCC_TXB_ECC_DB_ERR vBIT(0xff,24,8)
+#define PCC_SM_ERR_ALARM vBIT(0xff,32,8)
+#define PCC_WR_ERR_ALARM vBIT(0xff,40,8)
+#define PCC_N_SERR vBIT(0xff,48,8)
+#define PCC_6_COF_OV_ERR BIT(56)
+#define PCC_7_COF_OV_ERR BIT(57)
+#define PCC_6_LSO_OV_ERR BIT(58)
+#define PCC_7_LSO_OV_ERR BIT(59)
#define PCC_ENABLE_FOUR vBIT(0x0F,0,8)
-
u64 pcc_err_mask;
u64 pcc_err_alarm;
u64 tti_err_reg;
+#define TTI_ECC_SG_ERR BIT(7)
+#define TTI_ECC_DB_ERR BIT(15)
+#define TTI_SM_ERR_ALARM BIT(23)
u64 tti_err_mask;
u64 tti_err_alarm;
u64 lso_err_reg;
+#define LSO6_SEND_OFLOW BIT(12)
+#define LSO7_SEND_OFLOW BIT(13)
+#define LSO6_ABORT BIT(14)
+#define LSO7_ABORT BIT(15)
+#define LSO6_SM_ERR_ALARM BIT(22)
+#define LSO7_SM_ERR_ALARM BIT(23)
u64 lso_err_mask;
u64 lso_err_alarm;
u64 tpa_err_reg;
+#define TPA_TX_FRM_DROP BIT(7)
+#define TPA_SM_ERR_ALARM BIT(23)
u64 tpa_err_mask;
u64 tpa_err_alarm;
u64 sm_err_reg;
+#define SM_SM_ERR_ALARM BIT(15)
u64 sm_err_mask;
u64 sm_err_alarm;
@@ -450,22 +482,52 @@ struct XENA_dev_config {
#define RXDMA_INT_RTI_INT_M BIT(3)
u64 rda_err_reg;
+#define RDA_RXDn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RDA_RXDn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RDA_FRM_ECC_SG_ERR BIT(23)
+#define RDA_FRM_ECC_DB_N_AERR BIT(31)
+#define RDA_SM1_ERR_ALARM BIT(38)
+#define RDA_SM0_ERR_ALARM BIT(39)
+#define RDA_MISC_ERR BIT(47)
+#define RDA_PCIX_ERR BIT(55)
+#define RDA_RXD_ECC_DB_SERR BIT(63)
u64 rda_err_mask;
u64 rda_err_alarm;
u64 rc_err_reg;
+#define RC_PRCn_ECC_SG_ERR vBIT(0xFF,0,8)
+#define RC_PRCn_ECC_DB_ERR vBIT(0xFF,8,8)
+#define RC_FTC_ECC_SG_ERR BIT(23)
+#define RC_FTC_ECC_DB_ERR BIT(31)
+#define RC_PRCn_SM_ERR_ALARM vBIT(0xFF,32,8)
+#define RC_FTC_SM_ERR_ALARM BIT(47)
+#define RC_RDA_FAIL_WR_Rn vBIT(0xFF,48,8)
u64 rc_err_mask;
u64 rc_err_alarm;
u64 prc_pcix_err_reg;
+#define PRC_PCI_AB_RD_Rn vBIT(0xFF,0,8)
+#define PRC_PCI_DP_RD_Rn vBIT(0xFF,8,8)
+#define PRC_PCI_AB_WR_Rn vBIT(0xFF,16,8)
+#define PRC_PCI_DP_WR_Rn vBIT(0xFF,24,8)
+#define PRC_PCI_AB_F_WR_Rn vBIT(0xFF,32,8)
+#define PRC_PCI_DP_F_WR_Rn vBIT(0xFF,40,8)
u64 prc_pcix_err_mask;
u64 prc_pcix_err_alarm;
u64 rpa_err_reg;
+#define RPA_ECC_SG_ERR BIT(7)
+#define RPA_ECC_DB_ERR BIT(15)
+#define RPA_FLUSH_REQUEST BIT(22)
+#define RPA_SM_ERR_ALARM BIT(23)
+#define RPA_CREDIT_ERR BIT(31)
u64 rpa_err_mask;
u64 rpa_err_alarm;
u64 rti_err_reg;
+#define RTI_ECC_SG_ERR BIT(7)
+#define RTI_ECC_DB_ERR BIT(15)
+#define RTI_SM_ERR_ALARM BIT(23)
u64 rti_err_mask;
u64 rti_err_alarm;
@@ -582,17 +644,42 @@ struct XENA_dev_config {
#define MAC_INT_STATUS_RMAC_INT BIT(1)
u64 mac_tmac_err_reg;
-#define TMAC_ERR_REG_TMAC_ECC_DB_ERR BIT(15)
-#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN BIT(23)
-#define TMAC_ERR_REG_TMAC_TX_CRI_ERR BIT(31)
+#define TMAC_ECC_SG_ERR BIT(7)
+#define TMAC_ECC_DB_ERR BIT(15)
+#define TMAC_TX_BUF_OVRN BIT(23)
+#define TMAC_TX_CRI_ERR BIT(31)
+#define TMAC_TX_SM_ERR BIT(39)
+#define TMAC_DESC_ECC_SG_ERR BIT(47)
+#define TMAC_DESC_ECC_DB_ERR BIT(55)
u64 mac_tmac_err_mask;
u64 mac_tmac_err_alarm;
u64 mac_rmac_err_reg;
-#define RMAC_ERR_REG_RX_BUFF_OVRN BIT(0)
-#define RMAC_ERR_REG_RTS_ECC_DB_ERR BIT(14)
-#define RMAC_ERR_REG_ECC_DB_ERR BIT(15)
-#define RMAC_LINK_STATE_CHANGE_INT BIT(31)
+#define RMAC_RX_BUFF_OVRN BIT(0)
+#define RMAC_FRM_RCVD_INT BIT(1)
+#define RMAC_UNUSED_INT BIT(2)
+#define RMAC_RTS_PNUM_ECC_SG_ERR BIT(5)
+#define RMAC_RTS_DS_ECC_SG_ERR BIT(6)
+#define RMAC_RD_BUF_ECC_SG_ERR BIT(7)
+#define RMAC_RTH_MAP_ECC_SG_ERR BIT(8)
+#define RMAC_RTH_SPDM_ECC_SG_ERR BIT(9)
+#define RMAC_RTS_VID_ECC_SG_ERR BIT(10)
+#define RMAC_DA_SHADOW_ECC_SG_ERR BIT(11)
+#define RMAC_RTS_PNUM_ECC_DB_ERR BIT(13)
+#define RMAC_RTS_DS_ECC_DB_ERR BIT(14)
+#define RMAC_RD_BUF_ECC_DB_ERR BIT(15)
+#define RMAC_RTH_MAP_ECC_DB_ERR BIT(16)
+#define RMAC_RTH_SPDM_ECC_DB_ERR BIT(17)
+#define RMAC_RTS_VID_ECC_DB_ERR BIT(18)
+#define RMAC_DA_SHADOW_ECC_DB_ERR BIT(19)
+#define RMAC_LINK_STATE_CHANGE_INT BIT(31)
+#define RMAC_RX_SM_ERR BIT(39)
+#define RMAC_SINGLE_ECC_ERR (BIT(5) | BIT(6) | BIT(7) |\
+ BIT(8) | BIT(9) | BIT(10)|\
+ BIT(11))
+#define RMAC_DOUBLE_ECC_ERR (BIT(13) | BIT(14) | BIT(15) |\
+ BIT(16) | BIT(17) | BIT(18)|\
+ BIT(19))
u64 mac_rmac_err_mask;
u64 mac_rmac_err_alarm;
@@ -750,6 +837,8 @@ struct XENA_dev_config {
BIT(17) | BIT(19))
#define MC_ERR_REG_ECC_ALL_DBL (BIT(10) | BIT(11) | BIT(12) |\
BIT(13) | BIT(18) | BIT(20))
+#define PLL_LOCK_N BIT(39)
+
u64 mc_err_mask;
u64 mc_err_alarm;
@@ -823,11 +912,16 @@ struct XENA_dev_config {
#define XGXS_INT_MASK_RXGXS BIT(1)
u64 xgxs_txgxs_err_reg;
-#define TXGXS_ECC_DB_ERR BIT(15)
+#define TXGXS_ECC_SG_ERR BIT(7)
+#define TXGXS_ECC_DB_ERR BIT(15)
+#define TXGXS_ESTORE_UFLOW BIT(31)
+#define TXGXS_TX_SM_ERR BIT(39)
u64 xgxs_txgxs_err_mask;
u64 xgxs_txgxs_err_alarm;
u64 xgxs_rxgxs_err_reg;
+#define RXGXS_ESTORE_OFLOW BIT(7)
+#define RXGXS_RX_SM_ERR BIT(39)
u64 xgxs_rxgxs_err_mask;
u64 xgxs_rxgxs_err_alarm;
^ permalink raw reply
* [PATCH 9/14] nes: kernel to userspace structures
From: ggrundstrom @ 2007-08-08 1:14 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Kernel to userspace includes, structures and defines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_user.h
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_user.h 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect. All rights reserved.
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_USER_H
+#define NES_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct nes_alloc_ucontext_resp {
+ __u32 max_pds; /* maximum pds allowed for this user process */
+ __u32 max_qps; /* maximum qps allowed for this user process */
+ __u32 wq_size; /* size of the WQs (sq+rq) allocated to the mmaped area */
+ __u32 reserved;
+};
+
+struct nes_alloc_pd_resp {
+ __u32 pd_id;
+ __u32 mmap_db_index;
+};
+
+struct nes_create_cq_req {
+ __u64 user_cq_buffer;
+};
+
+enum iwnes_memreg_type {
+ IWNES_MEMREG_TYPE_MEM = 0x0000,
+ IWNES_MEMREG_TYPE_QP = 0x0001,
+ IWNES_MEMREG_TYPE_CQ = 0x0002,
+ IWNES_MEMREG_TYPE_MW = 0x0003,
+ IWNES_MEMREG_TYPE_FMR = 0x0004,
+};
+
+struct nes_mem_reg_req {
+ __u32 reg_type; /* indicates if id is memory, QP or CQ */
+ __u32 reserved;
+};
+
+struct nes_create_cq_resp {
+ __u32 cq_id;
+ __u32 cq_size;
+ __u32 mmap_db_index;
+ __u32 reserved;
+};
+
+struct nes_create_qp_resp {
+ __u32 qp_id;
+ __u32 actual_sq_size;
+ __u32 actual_rq_size;
+ __u32 mmap_sq_db_index;
+ __u32 mmap_rq_db_index;
+ __u32 reserved;
+};
+
+#endif /* NES_USER_H */
^ permalink raw reply
* Re: [RFC] cubic: backoff after slow start
From: Injong Rhee @ 2007-08-08 0:57 UTC (permalink / raw)
To: Stephen Hemminger, Injong Rhee, Sangtae Ha; +Cc: netdev
In-Reply-To: <20070807143739.7badea0a@oldman>
Hi Stephen,
We have been working on slow start and we have a nice solution for this. We
will send you a patch and test results.
Thanks
Injong
----- Original Message -----
From: "Stephen Hemminger" <shemminger@linux-foundation.org>
To: "Injong Rhee" <rhee@eos.ncsu.edu>; "Sangtae Ha" <sha2@ncsu.edu>
Cc: <netdev@vger.kernel.org>
Sent: Tuesday, August 07, 2007 2:37 PM
Subject: [RFC] cubic: backoff after slow start
> CUBIC takes several unnecessary iterations to converge out of slow start.
> This
> is most noticable over a link where the bottleneck queue size is much
> larger than BDP,
> and the sender has to "fill the pipe" in slow start before the first loss.
> Typical
> consumer broadband links seem to have large (up to 2secs) of queue that
> needs
> to get filled before the first loss.
>
> A possible fix is to use a beta of .5 (same as original TCP) when leaving
> slow start. Originally, the Linux version didn't do slow start so it
> probably
> never was observed.
>
> --- a/net/ipv4/tcp_cubic.c 2007-08-02 12:16:22.000000000 +0100
> +++ b/net/ipv4/tcp_cubic.c 2007-08-03 15:57:12.000000000 +0100
> @@ -289,7 +289,11 @@ static u32 bictcp_recalc_ssthresh(struct
>
> ca->loss_cwnd = tp->snd_cwnd;
>
> - return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U);
> + /* Initial backoff when leaving slow start */
> + if (tp->snd_ssthresh == 0x7fffffff)
> + return max(tp->snd_cwnd >> 1U, 2U);
> + else
> + return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U);
> }
>
> static u32 bictcp_undo_cwnd(struct sock *sk)
>
^ permalink raw reply
* [PATCH 8/14] nes: nic device routines
From: ggrundstrom @ 2007-08-08 1:12 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Nic device routines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_nic.c
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_nic.c 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,1467 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+#include <net/tcp.h>
+
+#include <net/inet_common.h>
+#include <linux/inet.h>
+
+#include "nes.h"
+
+struct nic_qp_map nic_qp_mapping_0[] = {
+ {16,0,0,1},{24,4,0,0},{28,8,0,0},{32,12,0,0},
+ {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0},
+ {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+struct nic_qp_map nic_qp_mapping_1[] = {
+ {18,1,1,1},{25,5,1,0},{29,9,1,0},{33,13,1,0},
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+struct nic_qp_map nic_qp_mapping_2[] = {
+ {20,2,2,1},{26,6,2,0},{30,10,2,0},{34,14,2,0}
+};
+
+struct nic_qp_map nic_qp_mapping_3[] = {
+ {22,3,3,1},{27,7,3,0},{31,11,3,0},{35,15,3,0}
+};
+
+struct nic_qp_map nic_qp_mapping_4[] = {
+ {28,8,0,0},{32,12,0,0}
+};
+
+struct nic_qp_map nic_qp_mapping_5[] = {
+ {29,9,1,0},{33,13,1,0}
+};
+
+struct nic_qp_map nic_qp_mapping_6[] = {
+ {30,10,2,0},{34,14,2,0}
+};
+
+struct nic_qp_map nic_qp_mapping_7[] = {
+ {31,11,3,0},{35,15,3,0}
+};
+
+struct nic_qp_map *nic_qp_mapping_per_function[] = {
+ nic_qp_mapping_0, nic_qp_mapping_1, nic_qp_mapping_2, nic_qp_mapping_3,
+ nic_qp_mapping_4, nic_qp_mapping_5, nic_qp_mapping_6, nic_qp_mapping_7
+};
+
+extern int nics_per_function;
+
+static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+static int debug = -1;
+
+static int rdma_enabled = 0;
+extern atomic_t cm_connects;
+extern atomic_t cm_accepts;
+extern atomic_t cm_disconnects;
+extern atomic_t cm_closes;
+extern atomic_t cm_connecteds;
+extern atomic_t cm_connect_reqs;
+extern atomic_t cm_rejects;
+extern atomic_t mod_qp_timouts;
+extern atomic_t qps_created;
+extern atomic_t qps_destroyed;
+extern atomic_t sw_qps_destroyed;
+extern u32 mh_detected;
+
+static int nes_netdev_open(struct net_device *);
+static int nes_netdev_stop(struct net_device *);
+static int nes_netdev_start_xmit(struct sk_buff *, struct net_device *);
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *);
+static void nes_netdev_tx_timeout(struct net_device *);
+static int nes_netdev_set_mac_address(struct net_device *, void *);
+static int nes_netdev_change_mtu(struct net_device *, int);
+
+#ifdef NES_NAPI
+/**
+ * nes_netdev_poll
+ */
+static int nes_netdev_poll(struct net_device* netdev, int* budget)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq;
+
+ nesvnic->budget = *budget;
+ nesvnic->cqes_pending = 0;
+ nesvnic->rx_cqes_completed = 0;
+ nesvnic->cqe_allocs_pending = 0;
+
+ nes_nic_ce_handler(nesdev, nescq);
+
+ netdev->quota -= nesvnic->rx_cqes_completed;
+ *budget -= nesvnic->rx_cqes_completed;
+
+ if (0 == nesvnic->cqes_pending) {
+ netif_rx_complete(netdev);
+ /* clear out completed cqes and arm */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ nescq->cq_number | (nesvnic->cqe_allocs_pending << 16));
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+ } else {
+ /* clear out completed cqes but don't arm */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ nescq->cq_number | (nesvnic->cqe_allocs_pending << 16));
+ dprintk("%s: %s: exiting with work pending\n",
+ nesvnic->netdev->name, __FUNCTION__);
+ }
+
+ return(0 == nesvnic->cqes_pending) ? 0 : 1;
+}
+#endif
+
+
+/**
+ * nes_netdev_open - Activate the network interface; ifconfig
+ * ethx up.
+ */
+static int nes_netdev_open(struct net_device *netdev)
+{
+ u32 macaddr_low;
+ u16 macaddr_high;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ int ret;
+ int i;
+ struct nes_vnic *first_nesvnic;
+ u32 nic_active_bit;
+ u32 nic_active;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ dprintk("%s: netdev->destructor = %p, netdev->uninit = %p, netdev->neigh_setup = %p\n",
+ __FUNCTION__, netdev->destructor, netdev->uninit, netdev->neigh_setup);
+
+ assert(nesdev != NULL);
+
+ first_nesvnic = list_entry(nesdev->nesadapter->nesvnic_list[nesdev->mac_index].next,
+ struct nes_vnic, list);
+
+ if (netif_msg_ifup(nesvnic))
+ printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name);
+
+ ret = nes_init_nic_qp(nesdev, netdev);
+ if (ret) {
+ return(ret);
+ }
+
+ if ((!nesvnic->of_device_registered) && (nesvnic->rdma_enabled)) {
+ nesvnic->nesibdev = nes_init_ofa_device(netdev);
+ if (nesvnic->nesibdev == NULL) {
+ printk(KERN_ERR PFX "%s: nesvnic->nesibdev alloc failed", netdev->name);
+ } else {
+ nesvnic->nesibdev->nesvnic = nesvnic;
+ ret = nes_register_ofa_device(nesvnic->nesibdev);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: Unable to register RDMA device, ret = %d\n",
+ netdev->name, ret);
+ }
+ }
+ }
+ /* Set packet filters */
+ nic_active_bit = 1 << nesvnic->nic_index;
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+ nic_active |= nic_active_bit;
+ nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high += (u16)netdev->dev_addr[1];
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
+
+#define NES_MAX_PORT_COUNT 4
+ /* Program the various MAC regs */
+ for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
+ if (nesvnic->qp_nic_index[i] == 0xf) {
+ break;
+ }
+ dprintk("%s: i=%d, perfect filter table index= %d, PERF FILTER LOW"
+ " (Addr:%08X) = %08X, HIGH = %08X.\n",
+ __FUNCTION__,
+ i, nesvnic->qp_nic_index[i],
+ NES_IDX_PERFECT_FILTER_LOW+((nesvnic->perfect_filter_index + i) * 8),
+ macaddr_low,
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)nesvnic->nic_index) << 16)));
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_LOW + (nesvnic->qp_nic_index[i] * 8),
+ macaddr_low);
+ nes_write_indexed(nesdev,
+ NES_IDX_PERFECT_FILTER_HIGH + (nesvnic->qp_nic_index[i] * 8),
+ (u32)macaddr_high | NES_MAC_ADDR_VALID |
+ ((((u32)nesvnic->nic_index) << 16)));
+ }
+
+
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ nesvnic->nic_cq.cq_number);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+
+ if (first_nesvnic->linkup) {
+ /* Enable network packets */
+ nesvnic->linkup = 1;
+ netif_start_queue(netdev);
+ } else {
+ netif_carrier_off(netdev);
+ }
+ nesvnic->netdev_open = 1;
+
+ return (0);
+}
+
+
+/**
+ * nes_netdev_stop
+ */
+static int nes_netdev_stop(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 nic_active_mask;
+ u32 nic_active;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ if (0 == nesvnic->netdev_open)
+ return (0);
+
+ if (netif_msg_ifdown(nesvnic))
+ printk(KERN_INFO PFX "%s: disabling interface\n", netdev->name);
+
+ /* Disable network packets */
+ netif_stop_queue(netdev);
+ if ((nesdev->netdev[0] == netdev)&(nesvnic->logical_port == nesdev->mac_index)) {
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff);
+ }
+
+ nic_active_mask = ~((u32)(1 << nesvnic->nic_index));
+ nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_HIGH+
+ (nesvnic->perfect_filter_index*8), 0);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_ACTIVE);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_ACTIVE, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_MULTICAST_ALL, nic_active);
+ nic_active = nes_read_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON);
+ nic_active &= nic_active_mask;
+ nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
+
+
+ if (nesvnic->of_device_registered) {
+ nes_destroy_ofa_device(nesvnic->nesibdev);
+ nesvnic->nesibdev = NULL;
+ nesvnic->of_device_registered = 0;
+ rdma_enabled = 0;
+ }
+ nes_destroy_nic_qp(nesvnic);
+
+ nesvnic->netdev_open = 0;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * nes_nic_send
+ */
+static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic *nesnic = &nesvnic->nic;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+#ifdef NETIF_F_TSO
+ struct tcphdr *pTCPHeader;
+ /* struct udphdr *pUDPHeader; */
+#endif
+ u16 *wqe_fragment_length;
+ u64 *wqe_fragment_address;
+ u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
+ u16 skb_fragment_index;
+ dma_addr_t bus_address;
+
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+ wqe_fragment_length = (u16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+
+ /* setup the VLAN tag if present */
+ if (vlan_tx_tag_present(skb)) {
+ dprintk("%s:%s: VLAN packet to send... VLAN = %08X\n", netdev->name,
+ __FUNCTION__, vlan_tx_tag_get(skb));
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
+ cpu_to_le32(NES_NIC_SQ_WQE_TAGVALUE_ENABLE);
+ wqe_fragment_length[0] = vlan_tx_tag_get(skb);
+ } else
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] = 0;
+
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX];
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
+ if (skb->ip_summed == CHECKSUM_HW) {
+#else
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+#endif
+ pTCPHeader = skb->h.th;
+ if (1) {
+#ifdef NETIF_F_TSO
+ if (nes_skb_lso_size(skb)) {
+ /* dprintk("%s:%s: TSO request... seg size = %u\n", netdev->name,
+ __FUNCTION__, nes_skb_lso_size(skb)); */
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] |=
+ cpu_to_le32(NES_NIC_SQ_WQE_LSO_ENABLE |
+ NES_NIC_SQ_WQE_COMPLETION | (u16)nes_skb_lso_size(skb));
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LSO_INFO_IDX] =
+ cpu_to_le32(((u32)pTCPHeader->doff) |
+ (((u32)(((unsigned char *)pTCPHeader) - skb->data)) << 4));
+ } else {
+#endif
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] |=
+ cpu_to_le32(NES_NIC_SQ_WQE_COMPLETION);
+#ifdef NETIF_F_TSO
+ }
+#endif
+ }
+ } else { /* CHECKSUM_HW */
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] |=
+ cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION);
+ }
+
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX] = cpu_to_le32(skb->len);
+ memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+ skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), skb_headlen(skb)));
+ wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ skb_headlen(skb)));
+ wqe_fragment_length[1] = 0;
+ if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+ if ((skb_shinfo(skb)->nr_frags + 1) > 4) {
+ dprintk("%s: Packet with %u fragments not sent, skb_headlen=%u\n",
+ netdev->name, skb_shinfo(skb)->nr_frags + 2, skb_headlen(skb));
+ kfree_skb(skb);
+ nesvnic->tx_sw_dropped++;
+ return(NETDEV_TX_LOCKED);
+ }
+ bus_address = pci_map_single(nesdev->pcidev, skb->data + NES_FIRST_FRAG_SIZE,
+ skb_headlen(skb) - NES_FIRST_FRAG_SIZE, PCI_DMA_TODEVICE);
+ wqe_fragment_length[wqe_fragment_index] =
+ cpu_to_le16(skb_headlen(skb) - NES_FIRST_FRAG_SIZE);
+ wqe_fragment_length[wqe_fragment_index + 1] = 0;
+ wqe_fragment_address[wqe_fragment_index++] = cpu_to_le64(bus_address);
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ }
+
+ if (skb_headlen(skb) == skb->len) {
+ if (skb_headlen(skb) <= NES_FIRST_FRAG_SIZE) {
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = 0;
+ nesnic->tx_skb[nesnic->sq_head] = NULL;
+ dev_kfree_skb(skb);
+ }
+ } else {
+ /* Deal with Fragments */
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ for (skb_fragment_index = 0; skb_fragment_index < skb_shinfo(skb)->nr_frags;
+ skb_fragment_index++) {
+ bus_address = pci_map_page( nesdev->pcidev,
+ skb_shinfo(skb)->frags[skb_fragment_index].page,
+ skb_shinfo(skb)->frags[skb_fragment_index].page_offset,
+ skb_shinfo(skb)->frags[skb_fragment_index].size,
+ PCI_DMA_TODEVICE);
+ wqe_fragment_length[wqe_fragment_index] =
+ cpu_to_le16(skb_shinfo(skb)->frags[skb_fragment_index].size);
+ wqe_fragment_address[wqe_fragment_index++] = cpu_to_le64(bus_address);
+ if (wqe_fragment_index < 5)
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ }
+ }
+
+ nesnic->sq_head++;
+ nesnic->sq_head &= nesnic->sq_size - 1;
+
+ return(NETDEV_TX_OK);
+}
+
+
+/**
+ * nes_netdev_start_xmit
+ */
+static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_nic *nesnic = &nesvnic->nic;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+#ifdef NETIF_F_TSO
+ struct tcphdr *pTCPHeader;
+ /* struct udphdr *pUDPHeader; */
+#define NES_MAX_TSO_FRAGS 18
+ /* 64K segment plus overflow on each side */
+ dma_addr_t tso_bus_address[NES_MAX_TSO_FRAGS];
+ u32 tso_frag_index;
+ u32 tso_frag_count;
+ u32 tso_wqe_length;
+ u32 curr_tcp_seq;
+#endif
+ u32 wqe_count=1;
+ u32 send_rc;
+ struct iphdr *pIPHeader;
+ unsigned long flags;
+ u16 *wqe_fragment_length;
+ u64 *wqe_fragment_address;
+ /* first fragment (0) is used by copy buffer */
+ u16 wqe_fragment_index=1;
+ u16 hoffset;
+ u16 nhoffset;
+#ifdef NETIF_F_TSO
+ u16 wqes_needed;
+ u16 wqes_available;
+#endif
+ u32 old_head;
+
+ if (nes_debug_level & NES_DBG_TX) {
+ dprintk("%s: %s Request to tx NIC packet length %u, headlen %u,"
+ " (%u frags), tso_size=%u\n",
+ __FUNCTION__, netdev->name, skb->len, skb_headlen(skb),
+ skb_shinfo(skb)->nr_frags, nes_skb_lso_size(skb));
+ }
+ local_irq_save(flags);
+ if (!spin_trylock(&nesnic->sq_lock)) {
+ local_irq_restore(flags);
+ nesvnic->sq_locked++;
+ return (NETDEV_TX_LOCKED);
+ }
+
+ /* Check if SQ is full */
+ if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ nesvnic->sq_full++;
+ return (NETDEV_TX_BUSY);
+ }
+
+ /* Check if too many fragments */
+ if (unlikely((skb_shinfo(skb)->nr_frags) > 4)) {
+#ifdef NETIF_F_TSO
+ if (nes_skb_lso_size(skb) && (skb_headlen(skb) <= NES_FIRST_FRAG_SIZE)) {
+ nesvnic->segmented_tso_requests++;
+ nesvnic->tso_requests++;
+ old_head = nesnic->sq_head;
+ /* Basically 4 fragments available per WQE with extended fragments */
+ wqes_needed = skb_shinfo(skb)->nr_frags >> 2;
+ wqes_needed += (skb_shinfo(skb)->nr_frags&3)?1:0;
+ wqes_available = (((nesnic->sq_tail+nesnic->sq_size)-nesnic->sq_head) - 1) &
+ (nesnic->sq_size - 1);
+
+ if (unlikely(wqes_needed > wqes_available)) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ dprintk("%s: HNIC SQ full- TSO request has too many frags!\n",
+ netdev->name);
+ nesvnic->sq_full++;
+ return (NETDEV_TX_BUSY);
+ }
+ /* Map all the buffers */
+ for (tso_frag_count=0; tso_frag_count < skb_shinfo(skb)->nr_frags;
+ tso_frag_count++) {
+ tso_bus_address[tso_frag_count] = pci_map_page( nesdev->pcidev,
+ skb_shinfo(skb)->frags[tso_frag_count].page,
+ skb_shinfo(skb)->frags[tso_frag_count].page_offset,
+ skb_shinfo(skb)->frags[tso_frag_count].size,
+ PCI_DMA_TODEVICE);
+ }
+
+ tso_frag_index = 0;
+ curr_tcp_seq = ntohl(skb->h.th->seq);
+ hoffset = skb->h.raw - skb->data;
+ nhoffset = skb->nh.raw - skb->data;
+
+ for (wqe_count=0; wqe_count<((u32)wqes_needed); wqe_count++) {
+ tso_wqe_length = 0;
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_head];
+ wqe_fragment_length =
+ (u16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+ /* setup the VLAN tag if present */
+ if (vlan_tx_tag_present(skb)) {
+ dprintk("%s:%s: VLAN packet to send... VLAN = %08X\n",
+ netdev->name, __FUNCTION__, vlan_tx_tag_get(skb) );
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
+ cpu_to_le32(NES_NIC_SQ_WQE_TAGVALUE_ENABLE);
+ wqe_fragment_length[0] = vlan_tx_tag_get(skb);
+ } else
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] = 0;
+
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ wqe_fragment_address =
+ (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX];
+
+ /* Assumes header totally fits in allocated buffer and is in first fragment */
+ if (skb_headlen(skb) > NES_FIRST_FRAG_SIZE) {
+ dprintk("ERROR: SKB header too big, skb_headlen=%u, FIRST_FRAG_SIZE=%u\n",
+ skb_headlen(skb), NES_FIRST_FRAG_SIZE);
+ dprintk("%s: %s Request to tx NIC packet length %u, headlen %u,"
+ " (%u frags), tso_size=%u\n",
+ __FUNCTION__, netdev->name,
+ skb->len, skb_headlen(skb),
+ skb_shinfo(skb)->nr_frags, nes_skb_lso_size(skb));
+ }
+ memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer,
+ skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ skb_headlen(skb)));
+ pIPHeader = (struct iphdr *)
+ (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[nhoffset]);
+ pTCPHeader = (struct tcphdr *)
+ (&nesnic->first_frag_vbase[nesnic->sq_head].buffer[hoffset]);
+ if ((wqe_count+1)!=(u32)wqes_needed) {
+ pTCPHeader->fin = 0;
+ pTCPHeader->psh = 0;
+ pTCPHeader->rst = 0;
+ pTCPHeader->urg = 0;
+ }
+ if (wqe_count) {
+ pTCPHeader->syn = 0;
+ }
+ pTCPHeader->seq = htonl(curr_tcp_seq);
+ wqe_fragment_length[0] = cpu_to_le16(min(((unsigned int)NES_FIRST_FRAG_SIZE),
+ skb_headlen(skb)));
+
+ for (wqe_fragment_index = 1; wqe_fragment_index < 5;) {
+ wqe_fragment_length[wqe_fragment_index] =
+ cpu_to_le16(skb_shinfo(skb)->frags[tso_frag_index].size);
+ wqe_fragment_address[wqe_fragment_index++] =
+ cpu_to_le64(tso_bus_address[tso_frag_index]);
+ tso_wqe_length += skb_shinfo(skb)->frags[tso_frag_index++].size;
+ if (wqe_fragment_index < 5)
+ wqe_fragment_length[wqe_fragment_index] = 0;
+ if (tso_frag_index == tso_frag_count)
+ break;
+ }
+ if ((wqe_count+1) == (u32)wqes_needed) {
+ nesnic->tx_skb[nesnic->sq_head] = skb;
+ } else {
+ nesnic->tx_skb[nesnic->sq_head] = NULL;
+ }
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] |=
+ cpu_to_le32(NES_NIC_SQ_WQE_COMPLETION | (u16)nes_skb_lso_size(skb));
+ if ((tso_wqe_length + skb_headlen(skb)) > nes_skb_lso_size(skb)) {
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] |= cpu_to_le32(NES_NIC_SQ_WQE_LSO_ENABLE);
+ } else {
+ pIPHeader->tot_len = htons(tso_wqe_length + skb_headlen(skb) - nhoffset);
+ }
+
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LSO_INFO_IDX] =
+ cpu_to_le32(((u32)pTCPHeader->doff) | (((u32)hoffset) << 4));
+
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX] =
+ cpu_to_le32(tso_wqe_length+skb_headlen(skb));
+ curr_tcp_seq += tso_wqe_length;
+ nesnic->sq_head++;
+ nesnic->sq_head &= nesnic->sq_size-1;
+ }
+ } else {
+#endif
+ nesvnic->linearized_skbs++;
+ hoffset = skb->h.raw - skb->data;
+ nhoffset = skb->nh.raw - skb->data;
+ nes_skb_linearize(skb, GFP_ATOMIC);
+ skb->h.raw = skb->data + hoffset;
+ skb->nh.raw = skb->data + nhoffset;
+ send_rc = nes_nic_send(skb, netdev);
+ if (send_rc != NETDEV_TX_OK) {
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ return (NETDEV_TX_OK);
+ }
+#ifdef NETIF_F_TSO
+ }
+#endif
+ } else {
+ send_rc = nes_nic_send(skb, netdev);
+ if (send_rc != NETDEV_TX_OK) {
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ return (NETDEV_TX_OK);
+ }
+ }
+
+ barrier();
+
+ if (wqe_count)
+ nes_write32(nesdev->regs+NES_WQE_ALLOC,
+ (wqe_count << 24) | (1 << 23) | nesvnic->nic.qp_id);
+
+ netdev->trans_start = jiffies;
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+
+ return(NETDEV_TX_OK);
+}
+
+
+/**
+ * nes_netdev_get_stats
+ */
+static struct net_device_stats *nes_netdev_get_stats(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u64 u64temp;
+ u32 u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD + (nesvnic->nic_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->endnode_nstat_rx_discard += u32temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_octets += u64temp;
+ nesvnic->netstats.rx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_frames += u64temp;
+ nesvnic->netstats.rx_packets += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_octets += u64temp;
+ nesvnic->netstats.tx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO + (nesvnic->nic_index*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI + (nesvnic->nic_index*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_frames += u64temp;
+ nesvnic->netstats.tx_packets += u64temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_SHORT_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_short_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_OVERSIZED_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_oversized_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_JABBER_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_jabber_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_symbol_err_frames += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_LENGTH_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->netstats.rx_length_errors += u32temp;
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_CRC_ERR_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_rx_errors += u32temp;
+ nesvnic->nesdev->mac_rx_crc_errors += u32temp;
+ nesvnic->netstats.rx_crc_errors += u32temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_ERRORS + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_tx_errors += u32temp;
+ nesvnic->netstats.tx_errors += u32temp;
+
+ return(&nesvnic->netstats);
+}
+
+
+/**
+ * nes_netdev_tx_timeout
+ */
+static void nes_netdev_tx_timeout(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (netif_msg_timer(nesvnic))
+ dprintk(KERN_DEBUG PFX "%s: tx timeout\n", netdev->name);
+}
+
+
+/**
+ * nes_netdev_set_mac_address
+ */
+static int nes_netdev_set_mac_address(struct net_device *netdev, void *p)
+{
+ return (-1);
+}
+
+
+/**
+ * nes_netdev_change_mtu
+ */
+static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ int ret = 0;
+
+ if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
+ return (-EINVAL);
+
+ netdev->mtu = new_mtu;
+ nesvnic->max_frame_size = new_mtu+ETH_HLEN;
+
+ if (netif_running(netdev)) {
+ nes_netdev_stop(netdev);
+ nes_netdev_open(netdev);
+ }
+
+ return (ret);
+}
+
+
+/**
+ * nes_netdev_exit - destroy network device
+ */
+void nes_netdev_exit(struct nes_vnic *nesvnic)
+{
+ struct net_device *netdev = nesvnic->netdev;
+ struct nes_ib_device *nesibdev = nesvnic->nesibdev;
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ // destroy the ibdevice if RDMA enabled
+ if ((nesvnic->rdma_enabled)&&(nesvnic->of_device_registered)) {
+ nes_destroy_ofa_device( nesibdev );
+ nesvnic->of_device_registered = 0;
+ rdma_enabled = 0;
+ nesvnic->nesibdev = NULL;
+ }
+ unregister_netdev(netdev);
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+
+#define NES_ETHTOOL_STAT_COUNT 32
+static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = {
+ "Link Change Interrupts",
+ "Linearized SKBs",
+ "T/GSO Requests",
+ "Pause Frames Sent",
+ "Pause Frames Received",
+ "Internal Routing Errors",
+ "SQ SW Dropped SKBs",
+ "SQ Locked",
+ "SQ Full",
+ "Segmented TSO Requests",
+ "Rx Symbol Errors",
+ "Rx Jabber Errors",
+ "Rx Oversized Frames",
+ "Rx Short Frames",
+ "Endnode Rx Discards",
+ "Endnode Rx Octets",
+ "Endnode Rx Frames",
+ "Endnode Tx Octets",
+ "Endnode Tx Frames",
+ "mh detected",
+ "Retransmission Count",
+ "CM Connects",
+ "CM Accepts",
+ "Disconnects",
+ "Connected Events",
+ "Connect Requests",
+ "CM Rejects",
+ "ModifyQP Timeouts",
+ "CreateQPs",
+ "SW DestroyQPs",
+ "DestroyQPs",
+ "CM Closes",
+};
+
+
+/**
+ * nes_netdev_get_rx_csum
+ */
+static u32 nes_netdev_get_rx_csum (struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (nesvnic->rx_checksum_disabled)
+ return (0);
+ else
+ return (1);
+}
+
+
+/**
+ * nes_netdev_set_rc_csum
+ */
+static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ if (enable)
+ nesvnic->rx_checksum_disabled = 0;
+ else
+ nesvnic->rx_checksum_disabled = 1;
+ return (0);
+}
+
+
+/**
+ * nes_netdev_get_stats_count
+ */
+static int nes_netdev_get_stats_count(struct net_device *netdev)
+{
+ return (NES_ETHTOOL_STAT_COUNT);
+}
+
+
+/**
+ * nes_netdev_get_strings
+ */
+static void nes_netdev_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *ethtool_strings)
+{
+ if (stringset == ETH_SS_STATS)
+ memcpy(ethtool_strings,
+ &nes_ethtool_stringset,
+ sizeof(nes_ethtool_stringset));
+}
+
+
+/**
+ * nes_netdev_get_ethtool_stats
+ */
+static void nes_netdev_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *target_ethtool_stats, u64 *target_stat_values)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 nic_count;
+ u32 u32temp;
+
+ target_ethtool_stats->n_stats = NES_ETHTOOL_STAT_COUNT;
+ target_stat_values[0] = nesvnic->nesdev->link_status_interrupts;
+ target_stat_values[1] = nesvnic->linearized_skbs;
+ target_stat_values[2] = nesvnic->tso_requests;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_pause_frames_sent += u32temp;
+ target_stat_values[3] = nesvnic->nesdev->mac_pause_frames_sent;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_RX_PAUSE_FRAMES + (nesvnic->nesdev->mac_index*0x200));
+ nesvnic->nesdev->mac_pause_frames_received += u32temp;
+
+ for (nic_count = 0; nic_count < NES_MAX_PORT_COUNT; nic_count++) {
+ if (nesvnic->qp_nic_index[nic_count] == 0xf)
+ break;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ nesvnic->netstats.rx_dropped += u32temp;
+ nesvnic->endnode_nstat_rx_discard += u32temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_octets += u64temp;
+ nesvnic->netstats.rx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_rx_frames += u64temp;
+ nesvnic->netstats.rx_packets += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_octets += u64temp;
+ nesvnic->netstats.tx_bytes += u64temp;
+
+ u64temp = (u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO +
+ (nesvnic->qp_nic_index[nic_count]*0x200));
+ u64temp += ((u64)nes_read_indexed(nesdev,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI +
+ (nesvnic->qp_nic_index[nic_count]*0x200))) << 32;
+
+ nesvnic->endnode_nstat_tx_frames += u64temp;
+ nesvnic->netstats.tx_packets += u64temp;
+
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_IPV4_TCP_REXMITS + (nesvnic->qp_nic_index[nic_count]*0x200));
+ nesvnic->endnode_ipv4_tcp_retransmits += u32temp;
+ }
+
+ target_stat_values[4] = nesvnic->nesdev->mac_pause_frames_received;
+ target_stat_values[5] = nesdev->nesadapter->nic_rx_eth_route_err;
+ target_stat_values[6] = nesvnic->tx_sw_dropped;
+ target_stat_values[7] = nesvnic->sq_locked;
+ target_stat_values[8] = nesvnic->sq_full;
+ target_stat_values[9] = nesvnic->segmented_tso_requests;
+ target_stat_values[10] = nesvnic->nesdev->mac_rx_symbol_err_frames;
+ target_stat_values[11] = nesvnic->nesdev->mac_rx_jabber_frames;
+ target_stat_values[12] = nesvnic->nesdev->mac_rx_oversized_frames;
+ target_stat_values[13] = nesvnic->nesdev->mac_rx_short_frames;
+ target_stat_values[14] = nesvnic->endnode_nstat_rx_discard;
+ target_stat_values[15] = nesvnic->endnode_nstat_rx_octets;
+ target_stat_values[16] = nesvnic->endnode_nstat_rx_frames;
+ target_stat_values[17] = nesvnic->endnode_nstat_tx_octets;
+ target_stat_values[18] = nesvnic->endnode_nstat_tx_frames;
+ target_stat_values[19] = mh_detected;
+ target_stat_values[20] = nesvnic->endnode_ipv4_tcp_retransmits;
+ target_stat_values[21] = atomic_read(&cm_connects);
+ target_stat_values[22] = atomic_read(&cm_accepts);
+ target_stat_values[23] = atomic_read(&cm_disconnects);
+ target_stat_values[24] = atomic_read(&cm_connecteds);
+ target_stat_values[25] = atomic_read(&cm_connect_reqs);
+ target_stat_values[26] = atomic_read(&cm_rejects);
+ target_stat_values[27] = atomic_read(&mod_qp_timouts);
+ target_stat_values[28] = atomic_read(&qps_created);
+ target_stat_values[29] = atomic_read(&sw_qps_destroyed);
+ target_stat_values[30] = atomic_read(&qps_destroyed);
+ target_stat_values[31] = atomic_read(&cm_closes);
+}
+
+
+/**
+ * nes_netdev_get_drvinfo
+ */
+void nes_netdev_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ strcpy(drvinfo->driver, DRV_NAME);
+ strcpy(drvinfo->bus_info, pci_name(nesvnic->nesdev->pcidev));
+ strcpy(drvinfo->fw_version, "TBD");
+ strcpy(drvinfo->version, DRV_VERSION);
+ drvinfo->n_stats = nes_netdev_get_stats_count(netdev);
+ drvinfo->testinfo_len = 0;
+ drvinfo->eedump_len = 0;
+ drvinfo->regdump_len = 0;
+}
+
+
+/**
+ * nes_netdev_set_coalesce
+ */
+static int nes_netdev_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+
+ /* using this to drive total interrupt moderation */
+ nesvnic->nesdev->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
+ if (nesdev->et_rx_coalesce_usecs_irq) {
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
+ 0x80000000 | ((u32)(nesdev->et_rx_coalesce_usecs_irq*8)));
+ }
+ return (0);
+}
+
+
+/**
+ * nes_netdev_get_coalesce
+ */
+static int nes_netdev_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *et_coalesce)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct ethtool_coalesce temp_et_coalesce;
+
+ memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
+ temp_et_coalesce.rx_coalesce_usecs_irq = nesvnic->nesdev->et_rx_coalesce_usecs_irq;
+ memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
+ return (0);
+}
+
+
+/**
+ * nes_netdev_get_pauseparam
+ */
+void nes_netdev_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *et_pauseparam)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ et_pauseparam->autoneg = 0;
+ et_pauseparam->rx_pause = (nesvnic->nesdev->disable_rx_flow_control==0)?1:0;
+ et_pauseparam->tx_pause = (nesvnic->nesdev->disable_tx_flow_control==0)?1:0;
+}
+
+
+/**
+ * nes_netdev_set_pauseparam
+ */
+int nes_netdev_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *et_pauseparam)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 u32temp;
+
+ if (et_pauseparam->autoneg) {
+ /* TODO: should return unsupported */
+ return (0);
+ }
+ if ((et_pauseparam->tx_pause==1) && (nesdev->disable_tx_flow_control==1)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+ u32temp |= NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+ nesdev->disable_tx_flow_control = 0;
+ } else if ((et_pauseparam->tx_pause==0) && (nesdev->disable_tx_flow_control==0)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG + (nesdev->mac_index*0x200));
+ u32temp &= ~NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE + (nesdev->mac_index*0x200), u32temp);
+ nesdev->disable_tx_flow_control = 1;
+ }
+ if ((et_pauseparam->rx_pause==1) && (nesdev->disable_rx_flow_control==1)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+ u32temp &= ~NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+ nesdev->disable_rx_flow_control = 0;
+ } else if ((et_pauseparam->rx_pause==0) && (nesdev->disable_rx_flow_control==0)) {
+ u32temp = nes_read_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40));
+ u32temp |= NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE;
+ nes_write_indexed(nesdev,
+ NES_IDX_MPP_DEBUG + (nesdev->mac_index*0x40), u32temp);
+ nesdev->disable_rx_flow_control = 1;
+ }
+
+ return (0);
+}
+
+
+/**
+ * nes_netdev_get_settings
+ */
+int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u16 phy_data;
+
+ et_cmd->duplex = DUPLEX_FULL;
+ if (nesadapter->OneG_Mode) {
+ et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg;
+ et_cmd->speed = SPEED_1000;
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ &phy_data);
+ if (phy_data&0x1000) {
+ et_cmd->autoneg = AUTONEG_ENABLE;
+ } else {
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ }
+ et_cmd->transceiver = XCVR_EXTERNAL;
+ et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+ } else {
+ et_cmd->supported = SUPPORTED_10000baseT_Full;
+ et_cmd->advertising = ADVERTISED_10000baseT_Full;
+ et_cmd->speed = SPEED_10000;
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ et_cmd->transceiver = XCVR_INTERNAL;
+ et_cmd->phy_address = nesdev->mac_index;
+ }
+ et_cmd->port = PORT_MII;
+ et_cmd->maxtxpkt = 511;
+ et_cmd->maxrxpkt = 511;
+ return 0;
+}
+
+
+/**
+ * nes_netdev_set_settings
+ */
+int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u16 phy_data;
+
+ if (nesadapter->OneG_Mode) {
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ &phy_data);
+ if (et_cmd->autoneg) {
+ /* Turn on Full duplex, Autoneg, and restart autonegotiation */
+ phy_data |= 0x1300;
+ } else {
+ // Turn off autoneg
+ phy_data &= ~0x1000;
+ }
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
+ phy_data);
+ }
+
+ return 0;
+}
+
+
+/**
+ * nes_netdev_get_msglevel
+ */
+u32 nes_netdev_get_msglevel(struct net_device *netdev)
+{
+ return nes_debug_level;
+}
+
+
+/**
+ * nes_netdev_set_msglevel
+ */
+void nes_netdev_set_msglevel(struct net_device *netdev, u32 level)
+{
+ dprintk("%s[%u] Setting message level to: %u\n", __FUNCTION__, __LINE__, level);
+ nes_debug_level = level;
+}
+
+
+static struct ethtool_ops nes_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_settings = nes_netdev_get_settings,
+ .set_settings = nes_netdev_set_settings,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_rx_csum = nes_netdev_get_rx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_strings = nes_netdev_get_strings,
+ .get_stats_count = nes_netdev_get_stats_count,
+ .get_ethtool_stats = nes_netdev_get_ethtool_stats,
+ .get_drvinfo = nes_netdev_get_drvinfo,
+ .get_coalesce = nes_netdev_get_coalesce,
+ .set_coalesce = nes_netdev_set_coalesce,
+ .get_pauseparam = nes_netdev_get_pauseparam,
+ .set_pauseparam = nes_netdev_set_pauseparam,
+ .get_msglevel = nes_netdev_get_msglevel,
+ .set_msglevel = nes_netdev_set_msglevel,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_rx_csum = nes_netdev_set_rx_csum,
+ .set_sg = ethtool_op_set_sg,
+#ifdef NETIF_F_TSO
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+#endif
+};
+
+
+#ifdef NETIF_F_HW_VLAN_TX
+static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev = nesvnic->nesdev;
+ u32 u32temp;
+
+ nesvnic->vlan_grp = grp;
+
+ /* Enable/Disable VLAN Stripping */
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG);
+ if (grp)
+ u32temp &= 0xfdffffff;
+ else
+ u32temp |= 0x02000000;
+
+ nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp);
+}
+#endif
+
+
+/**
+ * nes_netdev_init - initialize network device
+ */
+struct net_device *nes_netdev_init(struct nes_device *nesdev,
+ void __iomem *mmio_addr)
+{
+ u64 u64temp;
+ struct nes_vnic *nesvnic = NULL;
+ struct net_device *netdev;
+ struct nic_qp_map *curr_qp_map;
+ u32 u32temp;
+
+ netdev = alloc_etherdev(sizeof(struct nes_vnic));
+ if (!netdev) {
+ printk(KERN_ERR PFX "nesvnic etherdev alloc failed");
+ return(NULL);
+ }
+
+ dprintk("%s: netdev = %p.\n", __FUNCTION__, netdev);
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev);
+
+ netdev->open = nes_netdev_open;
+ netdev->stop = nes_netdev_stop;
+ netdev->hard_start_xmit = nes_netdev_start_xmit;
+ netdev->get_stats = nes_netdev_get_stats;
+ netdev->tx_timeout = nes_netdev_tx_timeout;
+ netdev->set_mac_address = nes_netdev_set_mac_address;
+ netdev->change_mtu = nes_netdev_change_mtu;
+ netdev->watchdog_timeo = NES_TX_TIMEOUT;
+ netdev->irq = nesdev->pcidev->irq;
+ netdev->mtu = ETH_DATA_LEN;
+ netdev->hard_header_len = ETH_HLEN;
+ netdev->addr_len = ETH_ALEN;
+ netdev->type = ARPHRD_ETHER;
+ netdev->features = NETIF_F_HIGHDMA;
+ netdev->ethtool_ops = &nes_ethtool_ops;
+#ifdef NES_NAPI
+ netdev->poll = nes_netdev_poll;
+ netdev->weight = 128;
+#endif
+#ifdef NETIF_F_HW_VLAN_TX
+ dprintk("%s: Enabling VLAN Insert/Delete.\n", __FUNCTION__);
+ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->vlan_rx_register = nes_netdev_vlan_rx_register;
+#endif
+#ifdef NETIF_F_LLTX
+ netdev->features |= NETIF_F_LLTX;
+#endif
+
+ /* Fill in the port structure */
+ nesvnic = netdev_priv(netdev);
+
+ memset(nesvnic, 0, sizeof(*nesvnic));
+ nesvnic->netdev = netdev;
+ nesvnic->nesdev = nesdev;
+ nesvnic->msg_enable = netif_msg_init(debug, default_msg);
+ nesvnic->netdev_index = nesdev->netdev_count;
+ nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count;
+ nesvnic->max_frame_size = netdev->mtu+netdev->hard_header_len;
+
+ curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)];
+ nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid;
+ nesvnic->nic_index = curr_qp_map[nesdev->netdev_count].nic_index;
+ nesvnic->logical_port = curr_qp_map[nesdev->netdev_count].logical_port;
+
+ /* Setup the burned in MAC address */
+ u64temp = (u64)nesdev->nesadapter->mac_addr_low;
+ u64temp += ((u64)nesdev->nesadapter->mac_addr_high) << 32;
+ u64temp += nesvnic->nic_index;
+ netdev->dev_addr[0] = (u8)(u64temp>>40);
+ netdev->dev_addr[1] = (u8)(u64temp>>32);
+ netdev->dev_addr[2] = (u8)(u64temp>>24);
+ netdev->dev_addr[3] = (u8)(u64temp>>16);
+ netdev->dev_addr[4] = (u8)(u64temp>>8);
+ netdev->dev_addr[5] = (u8)u64temp;
+
+ if (nesvnic->logical_port < 2) {
+#ifdef NETIF_F_TSO
+ dprintk("%s: Enabling TSO \n", __FUNCTION__);
+ netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_IP_CSUM;
+#endif
+#ifdef NETIF_F_GSO
+ dprintk("%s: Enabling GSO \n", __FUNCTION__);
+ netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
+#endif
+ } else {
+ netdev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_IP_CSUM;
+ }
+
+ dprintk("%s: nesvnic = %p, reported features = 0x%lX, QPid = %d,"
+ " nic_index = %d, logical_port = %d, mac_index = %d.\n",
+ __FUNCTION__, nesvnic, (unsigned long)netdev->features, nesvnic->nic.qp_id,
+ nesvnic->nic_index, nesvnic->logical_port, nesdev->mac_index);
+
+ if (nesvnic->nesdev->nesadapter->port_count == 1) {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = nesvnic->nic_index + 1;
+ if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ } else {
+ nesvnic->qp_nic_index[2] = nesvnic->nic_index + 2;
+ nesvnic->qp_nic_index[3] = nesvnic->nic_index + 3;
+ }
+ } else {
+ if (nesvnic->nesdev->nesadapter->port_count == 2) {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = nesvnic->nic_index + 2;
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ } else {
+ nesvnic->qp_nic_index[0] = nesvnic->nic_index;
+ nesvnic->qp_nic_index[1] = 0xf;
+ nesvnic->qp_nic_index[2] = 0xf;
+ nesvnic->qp_nic_index[3] = 0xf;
+ }
+ }
+ nesvnic->next_qp_nic_index = 0;
+
+ if (0 == nesdev->netdev_count) {
+ if (rdma_enabled == 0) {
+ rdma_enabled = 1;
+ nesvnic->rdma_enabled = 1;
+ }
+ } else {
+ nesvnic->rdma_enabled = 0;
+ }
+ nesvnic->nic_cq.cq_number = nesvnic->nic.qp_id;
+ spin_lock_init(&nesvnic->tx_lock);
+ nesdev->netdev[nesdev->netdev_count] = netdev;
+
+ dprintk("%s: Adding nesvnic (%p) to the adapters nesvnic_list for MAC%d.\n",
+ __FUNCTION__, nesvnic, nesdev->mac_index);
+ list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
+
+ if ((0 == nesdev->netdev_count) &&
+ (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
+ dprintk("%s: Setting up PHY interrupt mask. Using register index 0x%04X\n",
+ __FUNCTION__,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)));
+ u32temp |= 0x00200000;
+ nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)), u32temp);
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200*(nesvnic->logical_port&1)) );
+ if (0x0f0f0000 == (u32temp&0x0f1f0000)) {
+ dprintk("%s: The Link is UP!!.\n", __FUNCTION__);
+ nesvnic->linkup = 1;
+ }
+ dprintk("%s: Setting up MAC interrupt mask.\n", __FUNCTION__);
+ /* clear the MAC interrupt status, assumes direct logical to physical mapping */
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port));
+ dprintk("Phy interrupt status = 0x%X.\n", u32temp);
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp);
+
+ nes_init_phy(nesdev);
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port),
+ ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT |
+ NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR));
+ }
+
+ return(netdev);
+}
+
+
+/**
+ * nes_netdev_destroy - destroy network device structure
+ */
+void nes_netdev_destroy(struct net_device *netdev)
+{
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ /* make sure 'stop' method is called by Linux stack */
+ /* nes_netdev_stop(netdev); */
+
+ list_del(&nesvnic->list);
+
+ if (nesvnic->of_device_registered) {
+ nes_destroy_ofa_device(nesvnic->nesibdev);
+ }
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+
+ free_netdev(netdev);
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+}
+
+
+/**
+ * nes_nic_cm_xmit -- CM calls this to send out pkts
+ */
+int nes_nic_cm_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ int ret;
+
+ ret = nes_netdev_start_xmit(skb, netdev);
+
+ if (ret) {
+ dprintk("%s:%s:%u Bad return code from nes_netdev_start_xmit %d\n",
+ __FILE__, __FUNCTION__, __LINE__, ret);
+ }
+
+ return(ret);
+}
^ permalink raw reply
* [PATCH 7/14] nes: hardware specific includes
From: ggrundstrom @ 2007-08-08 1:08 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Hardware structures and defines
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_hw.h
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_hw.h 2007-08-06 20:09:05.000000000 -0500
@@ -0,0 +1,1102 @@
+/*
+* Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+*
+* This software is available to you under a choice of one of two
+* licenses. You may choose to be licensed under the terms of the GNU
+* General Public License (GPL) Version 2, available from the file
+* COPYING in the main directory of this source tree, or the
+* OpenIB.org BSD license below:
+*
+* Redistribution and use in source and binary forms, with or
+* without modification, are permitted provided that the following
+* conditions are met:
+*
+* - Redistributions of source code must retain the above
+* copyright notice, this list of conditions and the following
+* disclaimer.
+*
+* - Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials
+* provided with the distribution.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+* SOFTWARE.
+*/
+
+#ifndef __NES_HW_H
+#define __NES_HW_H
+
+enum pci_regs {
+ NES_INT_STAT = 0x0000,
+ NES_INT_MASK = 0x0004,
+ NES_INT_PENDING = 0x0008,
+ NES_INTF_INT_STAT = 0x000C,
+ NES_INTF_INT_MASK = 0x0010,
+ NES_TIMER_STAT = 0x0014,
+ NES_PERIODIC_CONTROL = 0x0018,
+ NES_ONE_SHOT_CONTROL = 0x001C,
+ NES_EEPROM_COMMAND = 0x0020,
+ NES_EEPROM_DATA = 0x0024,
+ NES_SOFTWARE_RESET = 0x0030,
+ NES_CQ_ACK = 0x0034,
+ NES_WQE_ALLOC = 0x0040,
+ NES_CQE_ALLOC = 0x0044,
+};
+
+enum indexed_regs {
+ NES_IDX_CREATE_CQP_LOW = 0x0000,
+ NES_IDX_CREATE_CQP_HIGH = 0x0004,
+ NES_IDX_QP_CONTROL = 0x0040,
+ NES_IDX_FLM_CONTROL = 0x0080,
+ NES_IDX_INT_CPU_STATUS = 0x00a0,
+ NES_IDX_GPIO_CONTROL = 0x00f0,
+ NES_IDX_GPIO_DATA = 0x00f4,
+ NES_IDX_TCP_CONFIG0 = 0x01e4,
+ NES_IDX_TCP_TIMER_CONFIG = 0x01ec,
+ NES_IDX_TCP_NOW = 0x01f0,
+ NES_IDX_QP_MAX_CFG_SIZES = 0x0200,
+ NES_IDX_QP_CTX_SIZE = 0x0218,
+ NES_IDX_TCP_TIMER_SIZE0 = 0x0238,
+ NES_IDX_TCP_TIMER_SIZE1 = 0x0240,
+ NES_IDX_ARP_CACHE_SIZE = 0x0258,
+ NES_IDX_CQ_CTX_SIZE = 0x0260,
+ NES_IDX_MRT_SIZE = 0x0278,
+ NES_IDX_PBL_REGION_SIZE = 0x0280,
+ NES_IDX_IRRQ_COUNT = 0x02b0,
+ NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x02f0,
+ NES_IDX_RX_WINDOW_BUFFER_SIZE = 0x0300,
+ NES_IDX_DST_IP_ADDR = 0x0400,
+ NES_IDX_PCIX_DIAG = 0x08e8,
+ NES_IDX_MPP_DEBUG = 0x0a00,
+ NES_IDX_MPP_LB_DEBUG = 0x0b00,
+ NES_IDX_DENALI_CTL_22 = 0x1058,
+ NES_IDX_MAC_TX_CONTROL = 0x2000,
+ NES_IDX_MAC_TX_CONFIG = 0x2004,
+ NES_IDX_MAC_TX_PAUSE_QUANTA = 0x2008,
+ NES_IDX_MAC_RX_CONTROL = 0x200c,
+ NES_IDX_MAC_RX_CONFIG = 0x2010,
+ NES_IDX_MAC_EXACT_MATCH_BOTTOM = 0x201c,
+ NES_IDX_MAC_MDIO_CONTROL = 0x2084,
+ NES_IDX_MAC_TX_OCTETS_LOW = 0x2100,
+ NES_IDX_MAC_TX_OCTETS_HIGH = 0x2104,
+ NES_IDX_MAC_TX_FRAMES_LOW = 0x2108,
+ NES_IDX_MAC_TX_FRAMES_HIGH = 0x210c,
+ NES_IDX_MAC_TX_PAUSE_FRAMES = 0x2118,
+ NES_IDX_MAC_TX_ERRORS = 0x2138,
+ NES_IDX_MAC_RX_OCTETS_LOW = 0x213c,
+ NES_IDX_MAC_RX_OCTETS_HIGH = 0x2140,
+ NES_IDX_MAC_RX_FRAMES_LOW = 0x2144,
+ NES_IDX_MAC_RX_FRAMES_HIGH = 0x2148,
+ NES_IDX_MAC_RX_BC_FRAMES_LOW = 0x214c,
+ NES_IDX_MAC_RX_MC_FRAMES_HIGH = 0x2150,
+ NES_IDX_MAC_RX_PAUSE_FRAMES = 0x2154,
+ NES_IDX_MAC_RX_SHORT_FRAMES = 0x2174,
+ NES_IDX_MAC_RX_OVERSIZED_FRAMES = 0x2178,
+ NES_IDX_MAC_RX_JABBER_FRAMES = 0x217c,
+ NES_IDX_MAC_RX_CRC_ERR_FRAMES = 0x2180,
+ NES_IDX_MAC_RX_LENGTH_ERR_FRAMES = 0x2184,
+ NES_IDX_MAC_RX_SYMBOL_ERR_FRAMES = 0x2188,
+ NES_IDX_MAC_INT_STATUS = 0x21f0,
+ NES_IDX_MAC_INT_MASK = 0x21f4,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 = 0x2800,
+ NES_IDX_PHY_PCS_CONTROL_STATUS1 = 0x2a00,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL0 = 0x2808,
+ NES_IDX_ETH_SERDES_COMMON_CONTROL1 = 0x2a08,
+ NES_IDX_ETH_SERDES_COMMON_STATUS0 = 0x280c,
+ NES_IDX_ETH_SERDES_COMMON_STATUS1 = 0x2a0c,
+ NES_IDX_ETH_SERDES_TX_EMP0 = 0x2810,
+ NES_IDX_ETH_SERDES_TX_EMP1 = 0x2a10,
+ NES_IDX_ETH_SERDES_TX_DRIVE0 = 0x2814,
+ NES_IDX_ETH_SERDES_TX_DRIVE1 = 0x2a14,
+ NES_IDX_ETH_SERDES_RX_MODE0 = 0x2818,
+ NES_IDX_ETH_SERDES_RX_MODE1 = 0x2a18,
+ NES_IDX_ETH_SERDES_RX_SIGDET0 = 0x281c,
+ NES_IDX_ETH_SERDES_RX_SIGDET1 = 0x2a1c,
+ NES_IDX_ETH_SERDES_BYPASS0 = 0x2820,
+ NES_IDX_ETH_SERDES_BYPASS1 = 0x2a20,
+ NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0 = 0x2824,
+ NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1 = 0x2a24,
+ NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 = 0x2828,
+ NES_IDX_ETH_SERDES_RX_EQ_CONTROL1 = 0x2a28,
+ NES_IDX_ETH_SERDES_RX_EQ_STATUS0 = 0x282c,
+ NES_IDX_ETH_SERDES_RX_EQ_STATUS1 = 0x2a2c,
+ NES_IDX_ETH_SERDES_CDR_RESET0 = 0x2830,
+ NES_IDX_ETH_SERDES_CDR_RESET1 = 0x2a30,
+ NES_IDX_ETH_SERDES_CDR_CONTROL0 = 0x2834,
+ NES_IDX_ETH_SERDES_CDR_CONTROL1 = 0x2a34,
+ NES_IDX_ENDNODE0_NSTAT_RX_DISCARD = 0x3080,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_LO = 0x3000,
+ NES_IDX_ENDNODE0_NSTAT_RX_OCTETS_HI = 0x3004,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_LO = 0x3008,
+ NES_IDX_ENDNODE0_NSTAT_RX_FRAMES_HI = 0x300c,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_LO = 0x7000,
+ NES_IDX_ENDNODE0_NSTAT_TX_OCTETS_HI = 0x7004,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_LO = 0x7008,
+ NES_IDX_ENDNODE0_NSTAT_TX_FRAMES_HI = 0x700c,
+ NES_IDX_CM_CONFIG = 0x5100,
+ NES_IDX_NIC_LOGPORT_TO_PHYPORT = 0x6000,
+ NES_IDX_NIC_PHYPORT_TO_USW = 0x6008,
+ NES_IDX_NIC_ACTIVE = 0x6010,
+ NES_IDX_NIC_UNICAST_ALL = 0x6018,
+ NES_IDX_NIC_MULTICAST_ALL = 0x6020,
+ NES_IDX_NIC_MULTICAST_ENABLE = 0x6028,
+ NES_IDX_NIC_BROADCAST_ON = 0x6030,
+ NES_IDX_USED_CHUNKS_TX = 0x60b0,
+ NES_IDX_TX_POOL_SIZE = 0x60b8,
+ NES_IDX_QUAD_HASH_TABLE_SIZE = 0x6148,
+ NES_IDX_PERFECT_FILTER_LOW = 0x6200,
+ NES_IDX_PERFECT_FILTER_HIGH = 0x6204,
+ NES_IDX_IPV4_TCP_REXMITS = 0x7080,
+ NES_IDX_DEBUG_ERROR_CONTROL_STATUS = 0x913c,
+ NES_IDX_DEBUG_ERROR_MASKS0 = 0x9140,
+ NES_IDX_DEBUG_ERROR_MASKS1 = 0x9144,
+ NES_IDX_DEBUG_ERROR_MASKS2 = 0x9148,
+ NES_IDX_DEBUG_ERROR_MASKS3 = 0x914c,
+ NES_IDX_DEBUG_ERROR_MASKS4 = 0x9150,
+ NES_IDX_DEBUG_ERROR_MASKS5 = 0x9154,
+};
+
+#define NES_IDX_MAC_TX_CONFIG_ENABLE_PAUSE 1
+#define NES_IDX_MPP_DEBUG_PORT_DISABLE_PAUSE (1 << 17)
+
+enum nes_cqp_opcodes {
+ NES_CQP_CREATE_QP = 0x00,
+ NES_CQP_MODIFY_QP = 0x01,
+ NES_CQP_DESTROY_QP = 0x02,
+ NES_CQP_CREATE_CQ = 0x03,
+ NES_CQP_MODIFY_CQ = 0x04,
+ NES_CQP_DESTROY_CQ = 0x05,
+ NES_CQP_ALLOCATE_STAG = 0x09,
+ NES_CQP_REGISTER_STAG = 0x0a,
+ NES_CQP_QUERY_STAG = 0x0b,
+ NES_CQP_REGISTER_SHARED_STAG = 0x0c,
+ NES_CQP_DEALLOCATE_STAG = 0x0d,
+ NES_CQP_MANAGE_ARP_CACHE = 0x0f,
+ NES_CQP_SUSPEND_QPS = 0x11,
+ NES_CQP_UPLOAD_CONTEXT = 0x13,
+ NES_CQP_CREATE_CEQ = 0x16,
+ NES_CQP_DESTROY_CEQ = 0x18,
+ NES_CQP_CREATE_AEQ = 0x19,
+ NES_CQP_DESTROY_AEQ = 0x1b,
+ NES_CQP_LMI_ACCESS = 0x20,
+ NES_CQP_FLUSH_WQES = 0x22,
+ NES_CQP_MANAGE_APBVT = 0x23
+};
+
+enum nes_cqp_wqe_word_idx {
+ NES_CQP_WQE_OPCODE_IDX = 0,
+ NES_CQP_WQE_ID_IDX = 1,
+ NES_CQP_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_CQP_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_CQP_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_wqeword_idx {
+ NES_CQP_CQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_CQ_WQE_PBL_HIGH_IDX = 7,
+ NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX = 8,
+ NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX = 9,
+ NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX = 10,
+};
+
+enum nes_cqp_stag_wqeword_idx {
+ NES_CQP_STAG_WQE_PBL_BLK_COUNT_IDX = 1,
+ NES_CQP_STAG_WQE_LEN_HIGH_PD_IDX = 6,
+ NES_CQP_STAG_WQE_LEN_LOW_IDX = 7,
+ NES_CQP_STAG_WQE_STAG_IDX = 8,
+ NES_CQP_STAG_WQE_VA_LOW_IDX = 10,
+ NES_CQP_STAG_WQE_VA_HIGH_IDX = 11,
+ NES_CQP_STAG_WQE_PA_LOW_IDX = 12,
+ NES_CQP_STAG_WQE_PA_HIGH_IDX = 13,
+ NES_CQP_STAG_WQE_PBL_LEN_IDX = 14
+};
+
+#define NES_CQP_OP_IWARP_STATE_SHIFT 28
+
+enum nes_cqp_qp_bits {
+ NES_CQP_QP_ARP_VALID = (1<<8),
+ NES_CQP_QP_WINBUF_VALID = (1<<9),
+ NES_CQP_QP_CONTEXT_VALID = (1<<10),
+ NES_CQP_QP_ORD_VALID = (1<<11),
+ NES_CQP_QP_WINBUF_DATAIND_EN = (1<<12),
+ NES_CQP_QP_VIRT_WQS = (1<<13),
+ NES_CQP_QP_DEL_HTE = (1<<14),
+ NES_CQP_QP_CQS_VALID = (1<<15),
+ NES_CQP_QP_TYPE_TSA = 0,
+ NES_CQP_QP_TYPE_IWARP = (1<<16),
+ NES_CQP_QP_TYPE_CQP = (4<<16),
+ NES_CQP_QP_TYPE_NIC = (5<<16),
+ NES_CQP_QP_MSS_CHG = (1<<20),
+ NES_CQP_QP_STATIC_RESOURCES = (1<<21),
+ NES_CQP_QP_IGNORE_MW_BOUND = (1<<22),
+ NES_CQP_QP_VWQ_USE_LMI = (1<<23),
+ NES_CQP_QP_IWARP_STATE_IDLE = (1<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_RTS = (2<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_CLOSING = (3<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_TERMINATE = (5<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_ERROR = (6<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_IWARP_STATE_MASK = (7<<NES_CQP_OP_IWARP_STATE_SHIFT),
+ NES_CQP_QP_RESET = (1<<31),
+};
+
+enum nes_cqp_qp_wqe_word_idx {
+ NES_CQP_QP_WQE_CONTEXT_LOW_IDX = 6,
+ NES_CQP_QP_WQE_CONTEXT_HIGH_IDX = 7,
+ NES_CQP_QP_WQE_NEW_MSS_IDX = 15,
+};
+
+enum nes_nic_ctx_bits {
+ NES_NIC_CTX_RQ_SIZE_32 = (3<<8),
+ NES_NIC_CTX_RQ_SIZE_512 = (3<<8),
+ NES_NIC_CTX_SQ_SIZE_32 = (1<<10),
+ NES_NIC_CTX_SQ_SIZE_512 = (3<<10),
+};
+
+enum nes_nic_qp_ctx_word_idx {
+ NES_NIC_CTX_MISC_IDX = 0,
+ NES_NIC_CTX_SQ_LOW_IDX = 2,
+ NES_NIC_CTX_SQ_HIGH_IDX = 3,
+ NES_NIC_CTX_RQ_LOW_IDX = 4,
+ NES_NIC_CTX_RQ_HIGH_IDX = 5,
+};
+
+enum nes_cqp_cq_bits {
+ NES_CQP_CQ_CEQE_MASK = (1<<9),
+ NES_CQP_CQ_CEQ_VALID = (1<<10),
+ NES_CQP_CQ_RESIZE = (1<<11),
+ NES_CQP_CQ_CHK_OVERFLOW = (1<<12),
+ NES_CQP_CQ_4KB_CHUNK = (1<<14),
+ NES_CQP_CQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_stag_bits {
+ NES_CQP_STAG_VA_TO = (1<<9),
+ NES_CQP_STAG_DEALLOC_PBLS = (1<<10),
+ NES_CQP_STAG_PBL_BLK_SIZE = (1<<11),
+ NES_CQP_STAG_MR = (1<<13),
+ NES_CQP_STAG_RIGHTS_LOCAL_READ = (1<<16),
+ NES_CQP_STAG_RIGHTS_LOCAL_WRITE = (1<<17),
+ NES_CQP_STAG_RIGHTS_REMOTE_READ = (1<<18),
+ NES_CQP_STAG_RIGHTS_REMOTE_WRITE = (1<<19),
+ NES_CQP_STAG_RIGHTS_WINDOW_BIND = (1<<20),
+ NES_CQP_STAG_REM_ACC_EN = (1<<21),
+ NES_CQP_STAG_LEAVE_PENDING = (1<<31),
+};
+
+enum nes_cqp_ceq_wqeword_idx {
+ NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX = 1,
+ NES_CQP_CEQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_CEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_ceq_bits {
+ NES_CQP_CEQ_4KB_CHUNK = (1<<14),
+ NES_CQP_CEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_aeq_wqeword_idx {
+ NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX = 1,
+ NES_CQP_AEQ_WQE_PBL_LOW_IDX = 6,
+ NES_CQP_AEQ_WQE_PBL_HIGH_IDX = 7,
+};
+
+enum nes_cqp_aeq_bits {
+ NES_CQP_AEQ_4KB_CHUNK = (1<<14),
+ NES_CQP_AEQ_VIRT = (1<<15),
+};
+
+enum nes_cqp_lmi_wqeword_idx {
+ NES_CQP_LMI_WQE_LMI_OFFSET_IDX = 1,
+ NES_CQP_LMI_WQE_FRAG_LOW_IDX = 8,
+ NES_CQP_LMI_WQE_FRAG_HIGH_IDX = 9,
+ NES_CQP_LMI_WQE_FRAG_LEN_IDX = 10,
+};
+
+enum nes_cqp_arp_wqeword_idx {
+ NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX = 6,
+ NES_CQP_ARP_WQE_MAC_HIGH_IDX = 7,
+ NES_CQP_ARP_WQE_REACHABILITY_MAX_IDX = 1,
+};
+
+enum nes_cqp_upload_wqeword_idx {
+ NES_CQP_UPLOAD_WQE_CTXT_LOW_IDX = 6,
+ NES_CQP_UPLOAD_WQE_CTXT_HIGH_IDX = 7,
+ NES_CQP_UPLOAD_WQE_HTE_IDX = 8,
+};
+
+enum nes_cqp_arp_bits {
+ NES_CQP_ARP_VALID = (1<<8),
+ NES_CQP_ARP_PERM = (1<<9),
+};
+
+enum nes_cqp_flush_bits {
+ NES_CQP_FLUSH_SQ = (1<<30),
+ NES_CQP_FLUSH_RQ = (1<<31),
+};
+
+enum nes_cqe_opcode_bits {
+ NES_CQE_STAG_VALID = (1<<6),
+ NES_CQE_ERROR = (1<<7),
+ NES_CQE_SQ = (1<<8),
+ NES_CQE_SE = (1<<9),
+ NES_CQE_PSH = (1<<29),
+ NES_CQE_FIN = (1<<30),
+ NES_CQE_VALID = (1<<31),
+};
+
+enum nes_cqe_word_idx {
+ NES_CQE_PAYLOAD_LENGTH_IDX = 0,
+ NES_CQE_COMP_COMP_CTX_LOW_IDX = 2,
+ NES_CQE_COMP_COMP_CTX_HIGH_IDX = 3,
+ NES_CQE_INV_STAG_IDX = 4,
+ NES_CQE_QP_ID_IDX = 5,
+ NES_CQE_ERROR_CODE_IDX = 6,
+ NES_CQE_OPCODE_IDX = 7,
+};
+
+enum nes_ceqe_word_idx {
+ NES_CEQE_CQ_CTX_LOW_IDX = 0,
+ NES_CEQE_CQ_CTX_HIGH_IDX = 1,
+};
+
+enum nes_ceqe_status_bit {
+ NES_CEQE_VALID = (1<<31),
+};
+
+enum nes_int_bits {
+ NES_INT_CEQ0 = (1<<0),
+ NES_INT_CEQ1 = (1<<1),
+ NES_INT_CEQ2 = (1<<2),
+ NES_INT_CEQ3 = (1<<3),
+ NES_INT_CEQ4 = (1<<4),
+ NES_INT_CEQ5 = (1<<5),
+ NES_INT_CEQ6 = (1<<6),
+ NES_INT_CEQ7 = (1<<7),
+ NES_INT_CEQ8 = (1<<8),
+ NES_INT_CEQ9 = (1<<9),
+ NES_INT_CEQ10 = (1<<10),
+ NES_INT_CEQ11 = (1<<11),
+ NES_INT_CEQ12 = (1<<12),
+ NES_INT_CEQ13 = (1<<13),
+ NES_INT_CEQ14 = (1<<14),
+ NES_INT_CEQ15 = (1<<15),
+ NES_INT_AEQ0 = (1<<16),
+ NES_INT_AEQ1 = (1<<17),
+ NES_INT_AEQ2 = (1<<18),
+ NES_INT_AEQ3 = (1<<19),
+ NES_INT_AEQ4 = (1<<20),
+ NES_INT_AEQ5 = (1<<21),
+ NES_INT_AEQ6 = (1<<22),
+ NES_INT_AEQ7 = (1<<23),
+ NES_INT_MAC0 = (1<<24),
+ NES_INT_MAC1 = (1<<25),
+ NES_INT_MAC2 = (1<<26),
+ NES_INT_MAC3 = (1<<27),
+ NES_INT_TSW = (1<<28),
+ NES_INT_TIMER = (1<<29),
+ NES_INT_INTF = (1<<30),
+};
+
+enum nes_intf_int_bits {
+ NES_INTF_INT_PCIERR = (1<<0),
+ NES_INTF_PERIODIC_TIMER = (1<<2),
+ NES_INTF_ONE_SHOT_TIMER = (1<<3),
+ NES_INTF_INT_CRITERR = (1<<14),
+ NES_INTF_INT_AEQ0_OFLOW = (1<<16),
+ NES_INTF_INT_AEQ1_OFLOW = (1<<17),
+ NES_INTF_INT_AEQ2_OFLOW = (1<<18),
+ NES_INTF_INT_AEQ3_OFLOW = (1<<19),
+ NES_INTF_INT_AEQ4_OFLOW = (1<<20),
+ NES_INTF_INT_AEQ5_OFLOW = (1<<21),
+ NES_INTF_INT_AEQ6_OFLOW = (1<<22),
+ NES_INTF_INT_AEQ7_OFLOW = (1<<23),
+ NES_INTF_INT_AEQ_OFLOW = (0xff<<16),
+};
+
+enum nes_mac_int_bits {
+ NES_MAC_INT_LINK_STAT_CHG = (1<<1),
+ NES_MAC_INT_XGMII_EXT = (1<<2),
+ NES_MAC_INT_TX_UNDERFLOW = (1<<6),
+ NES_MAC_INT_TX_ERROR = (1<<7),
+};
+
+enum nes_cqe_allocate_bits {
+ NES_CQE_ALLOC_INC_SELECT = (1<<28),
+ NES_CQE_ALLOC_NOTIFY_NEXT = (1<<29),
+ NES_CQE_ALLOC_NOTIFY_SE = (1<<30),
+ NES_CQE_ALLOC_RESET = (1<<31),
+};
+
+enum nes_nic_rq_wqe_word_idx {
+ NES_NIC_RQ_WQE_LENGTH_1_0_IDX = 0,
+ NES_NIC_RQ_WQE_LENGTH_3_2_IDX = 1,
+ NES_NIC_RQ_WQE_FRAG0_LOW_IDX = 2,
+ NES_NIC_RQ_WQE_FRAG0_HIGH_IDX = 3,
+ NES_NIC_RQ_WQE_FRAG1_LOW_IDX = 4,
+ NES_NIC_RQ_WQE_FRAG1_HIGH_IDX = 5,
+ NES_NIC_RQ_WQE_FRAG2_LOW_IDX = 6,
+ NES_NIC_RQ_WQE_FRAG2_HIGH_IDX = 7,
+ NES_NIC_RQ_WQE_FRAG3_LOW_IDX = 8,
+ NES_NIC_RQ_WQE_FRAG3_HIGH_IDX = 9,
+};
+
+enum nes_nic_sq_wqe_word_idx {
+ NES_NIC_SQ_WQE_MISC_IDX = 0,
+ NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX = 1,
+ NES_NIC_SQ_WQE_LSO_INFO_IDX = 2,
+ NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX = 3,
+ NES_NIC_SQ_WQE_LENGTH_2_1_IDX = 4,
+ NES_NIC_SQ_WQE_LENGTH_4_3_IDX = 5,
+ NES_NIC_SQ_WQE_FRAG0_LOW_IDX = 6,
+ NES_NIC_SQ_WQE_FRAG0_HIGH_IDX = 7,
+ NES_NIC_SQ_WQE_FRAG1_LOW_IDX = 8,
+ NES_NIC_SQ_WQE_FRAG1_HIGH_IDX = 9,
+ NES_NIC_SQ_WQE_FRAG2_LOW_IDX = 10,
+ NES_NIC_SQ_WQE_FRAG2_HIGH_IDX = 11,
+ NES_NIC_SQ_WQE_FRAG3_LOW_IDX = 12,
+ NES_NIC_SQ_WQE_FRAG3_HIGH_IDX = 13,
+ NES_NIC_SQ_WQE_FRAG4_LOW_IDX = 14,
+ NES_NIC_SQ_WQE_FRAG4_HIGH_IDX = 15,
+};
+
+enum nes_iwarp_sq_wqe_word_idx {
+ NES_IWARP_SQ_WQE_MISC_IDX = 0,
+ NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+ NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_IWARP_SQ_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_IWARP_SQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_IWARP_SQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+ NES_IWARP_SQ_WQE_INV_STAG_LOW_IDX = 7,
+ NES_IWARP_SQ_WQE_RDMA_TO_LOW_IDX = 8,
+ NES_IWARP_SQ_WQE_RDMA_TO_HIGH_IDX = 9,
+ NES_IWARP_SQ_WQE_RDMA_LENGTH_IDX = 10,
+ NES_IWARP_SQ_WQE_RDMA_STAG_IDX = 11,
+ NES_IWARP_SQ_WQE_IMM_DATA_START_IDX = 12,
+ NES_IWARP_SQ_WQE_FRAG0_LOW_IDX = 16,
+ NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX = 17,
+ NES_IWARP_SQ_WQE_LENGTH0_IDX = 18,
+ NES_IWARP_SQ_WQE_STAG0_IDX = 19,
+ NES_IWARP_SQ_WQE_FRAG1_LOW_IDX = 20,
+ NES_IWARP_SQ_WQE_FRAG1_HIGH_IDX = 21,
+ NES_IWARP_SQ_WQE_LENGTH1_IDX = 22,
+ NES_IWARP_SQ_WQE_STAG1_IDX = 23,
+ NES_IWARP_SQ_WQE_FRAG2_LOW_IDX = 24,
+ NES_IWARP_SQ_WQE_FRAG2_HIGH_IDX = 25,
+ NES_IWARP_SQ_WQE_LENGTH2_IDX = 26,
+ NES_IWARP_SQ_WQE_STAG2_IDX = 27,
+ NES_IWARP_SQ_WQE_FRAG3_LOW_IDX = 28,
+ NES_IWARP_SQ_WQE_FRAG3_HIGH_IDX = 29,
+ NES_IWARP_SQ_WQE_LENGTH3_IDX = 30,
+ NES_IWARP_SQ_WQE_STAG3_IDX = 31,
+};
+
+enum nes_iwarp_sq_bind_wqe_word_idx {
+ NES_IWARP_SQ_BIND_WQE_MR_IDX = 6,
+ NES_IWARP_SQ_BIND_WQE_MW_IDX = 7,
+ NES_IWARP_SQ_BIND_WQE_LENGTH_LOW_IDX = 8,
+ NES_IWARP_SQ_BIND_WQE_LENGTH_HIGH_IDX = 9,
+ NES_IWARP_SQ_BIND_WQE_VA_FBO_LOW_IDX = 10,
+ NES_IWARP_SQ_BIND_WQE_VA_FBO_HIGH_IDX = 11,
+};
+
+enum nes_iwarp_rq_wqe_word_idx {
+ NES_IWARP_RQ_WQE_TOTAL_PAYLOAD_IDX = 1,
+ NES_IWARP_RQ_WQE_COMP_CTX_LOW_IDX = 2,
+ NES_IWARP_RQ_WQE_COMP_CTX_HIGH_IDX = 3,
+ NES_IWARP_RQ_WQE_COMP_SCRATCH_LOW_IDX = 4,
+ NES_IWARP_RQ_WQE_COMP_SCRATCH_HIGH_IDX = 5,
+ NES_IWARP_RQ_WQE_FRAG0_LOW_IDX = 8,
+ NES_IWARP_RQ_WQE_FRAG0_HIGH_IDX = 9,
+ NES_IWARP_RQ_WQE_LENGTH0_IDX = 10,
+ NES_IWARP_RQ_WQE_STAG0_IDX = 11,
+ NES_IWARP_RQ_WQE_FRAG1_LOW_IDX = 12,
+ NES_IWARP_RQ_WQE_FRAG1_HIGH_IDX = 13,
+ NES_IWARP_RQ_WQE_LENGTH1_IDX = 14,
+ NES_IWARP_RQ_WQE_STAG1_IDX = 15,
+ NES_IWARP_RQ_WQE_FRAG2_LOW_IDX = 16,
+ NES_IWARP_RQ_WQE_FRAG2_HIGH_IDX = 17,
+ NES_IWARP_RQ_WQE_LENGTH2_IDX = 18,
+ NES_IWARP_RQ_WQE_STAG2_IDX = 19,
+ NES_IWARP_RQ_WQE_FRAG3_LOW_IDX = 20,
+ NES_IWARP_RQ_WQE_FRAG3_HIGH_IDX = 21,
+ NES_IWARP_RQ_WQE_LENGTH3_IDX = 22,
+ NES_IWARP_RQ_WQE_STAG3_IDX = 23,
+};
+
+enum nes_nic_sq_wqe_bits {
+ NES_NIC_SQ_WQE_PHDR_CS_READY = (1<<21),
+ NES_NIC_SQ_WQE_LSO_ENABLE = (1<<22),
+ NES_NIC_SQ_WQE_TAGVALUE_ENABLE = (1<<23),
+ NES_NIC_SQ_WQE_DISABLE_CHKSUM = (1<<30),
+ NES_NIC_SQ_WQE_COMPLETION = (1<<31),
+};
+
+enum nes_nic_cqe_word_idx {
+ NES_NIC_CQE_ACCQP_ID_IDX = 0,
+ NES_NIC_CQE_TAG_PKT_TYPE_IDX = 2,
+ NES_NIC_CQE_MISC_IDX = 3,
+};
+
+#define NES_PKT_TYPE_APBVT_BITS 0xC112
+#define NES_PKT_TYPE_APBVT_MASK 0xff3e
+
+#define NES_PKT_TYPE_TCPV4_BITS 0x0110
+#define NES_PKT_TYPE_TCPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_UDPV4_BITS 0x0210
+#define NES_PKT_TYPE_UDPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_IPV4_BITS 0x0010
+#define NES_PKT_TYPE_IPV4_MASK 0x3f30
+
+#define NES_PKT_TYPE_OTHER_BITS 0x0000
+#define NES_PKT_TYPE_OTHER_MASK 0x0030
+
+#define NES_NIC_CQE_ERRV_SHIFT 16
+enum nes_nic_ev_bits {
+ NES_NIC_ERRV_BITS_MODE = (1<<0),
+ NES_NIC_ERRV_BITS_IPV4_CSUM_ERR = (1<<1),
+ NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR = (1<<2),
+ NES_NIC_ERRV_BITS_WQE_OVERRUN = (1<<3),
+ NES_NIC_ERRV_BITS_IPH_ERR = (1<<4),
+};
+
+enum nes_nic_cqe_bits {
+ NES_NIC_CQE_ERRV_MASK = (0xff<<NES_NIC_CQE_ERRV_SHIFT),
+ NES_NIC_CQE_SQ = (1<<24),
+ NES_NIC_CQE_ACCQP_PORT = (1<<28),
+ NES_NIC_CQE_ACCQP_VALID = (1<<29),
+ NES_NIC_CQE_TAG_VALID = (1<<30),
+ NES_NIC_CQE_VALID = (1<<31),
+};
+
+enum nes_aeqe_word_idx {
+ NES_AEQE_COMP_CTXT_LOW_IDX = 0,
+ NES_AEQE_COMP_CTXT_HIGH_IDX = 1,
+ NES_AEQE_COMP_QP_CQ_ID_IDX = 2,
+ NES_AEQE_MISC_IDX = 3,
+};
+
+enum nes_aeqe_bits {
+ NES_AEQE_QP = (1<<16),
+ NES_AEQE_CQ = (1<<17),
+ NES_AEQE_SQ = (1<<18),
+ NES_AEQE_INBOUND_RDMA = (1<<19),
+ NES_AEQE_IWARP_STATE_MASK = (7<<20),
+ NES_AEQE_TCP_STATE_MASK = (0xf<<24),
+ NES_AEQE_VALID = (1<<31),
+};
+
+#define NES_AEQE_IWARP_STATE_SHIFT 20
+#define NES_AEQE_TCP_STATE_SHIFT 24
+
+enum nes_aeqe_iwarp_state {
+ NES_AEQE_IWARP_STATE_NON_EXISTANT = 0,
+ NES_AEQE_IWARP_STATE_IDLE = 1,
+ NES_AEQE_IWARP_STATE_RTS = 2,
+ NES_AEQE_IWARP_STATE_CLOSING = 3,
+ NES_AEQE_IWARP_STATE_TERMINATE = 5,
+ NES_AEQE_IWARP_STATE_ERROR = 6
+};
+
+enum nes_aeqe_tcp_state {
+ NES_AEQE_TCP_STATE_NON_EXISTANT = 0,
+ NES_AEQE_TCP_STATE_CLOSED = 1,
+ NES_AEQE_TCP_STATE_LISTEN = 2,
+ NES_AEQE_TCP_STATE_SYN_SENT = 3,
+ NES_AEQE_TCP_STATE_SYN_RCVD = 4,
+ NES_AEQE_TCP_STATE_ESTABLISHED = 5,
+ NES_AEQE_TCP_STATE_CLOSE_WAIT = 6,
+ NES_AEQE_TCP_STATE_FIN_WAIT_1 = 7,
+ NES_AEQE_TCP_STATE_CLOSING = 8,
+ NES_AEQE_TCP_STATE_LAST_ACK = 9,
+ NES_AEQE_TCP_STATE_FIN_WAIT_2 = 10,
+ NES_AEQE_TCP_STATE_TIME_WAIT = 11
+};
+
+#define NES_TIMER_INT_LIMIT 2
+
+enum nes_aeqe_aeid {
+ NES_AEQE_AEID_AMP_UNALLOCATED_STAG = 0x0102,
+ NES_AEQE_AEID_AMP_INVALID_STAG = 0x0103,
+ NES_AEQE_AEID_AMP_BAD_QP = 0x0104,
+ NES_AEQE_AEID_AMP_BAD_PD = 0x0105,
+ NES_AEQE_AEID_AMP_BAD_STAG_KEY = 0x0106,
+ NES_AEQE_AEID_AMP_BAD_STAG_INDEX = 0x0107,
+ NES_AEQE_AEID_AMP_BOUNDS_VIOLATION = 0x0108,
+ NES_AEQE_AEID_AMP_RIGHTS_VIOLATION = 0x0109,
+ NES_AEQE_AEID_AMP_TO_WRAP = 0x010a,
+ NES_AEQE_AEID_AMP_FASTREG_SHARED = 0x010b,
+ NES_AEQE_AEID_AMP_FASTREG_VALID_STAG = 0x010c,
+ NES_AEQE_AEID_AMP_FASTREG_MW_STAG = 0x010d,
+ NES_AEQE_AEID_AMP_FASTREG_INVALID_RIGHTS = 0x010e,
+ NES_AEQE_AEID_AMP_FASTREG_PBL_TABLE_OVERFLOW = 0x010f,
+ NES_AEQE_AEID_AMP_FASTREG_INVALID_LENGTH = 0x0110,
+ NES_AEQE_AEID_AMP_INVALIDATE_SHARED = 0x0111,
+ NES_AEQE_AEID_AMP_INVALIDATE_NO_REMOTE_ACCESS_RIGHTS = 0x0112,
+ NES_AEQE_AEID_AMP_INVALIDATE_MR_WITH_BOUND_WINDOWS = 0x0113,
+ NES_AEQE_AEID_AMP_MWBIND_VALID_STAG = 0x0114,
+ NES_AEQE_AEID_AMP_MWBIND_OF_MR_STAG = 0x0115,
+ NES_AEQE_AEID_AMP_MWBIND_TO_ZERO_BASED_STAG = 0x0116,
+ NES_AEQE_AEID_AMP_MWBIND_TO_MW_STAG = 0x0117,
+ NES_AEQE_AEID_AMP_MWBIND_INVALID_RIGHTS = 0x0118,
+ NES_AEQE_AEID_AMP_MWBIND_INVALID_BOUNDS = 0x0119,
+ NES_AEQE_AEID_AMP_MWBIND_TO_INVALID_PARENT = 0x011a,
+ NES_AEQE_AEID_AMP_MWBIND_BIND_DISABLED = 0x011b,
+ NES_AEQE_AEID_BAD_CLOSE = 0x0201,
+ NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE = 0x0202,
+ NES_AEQE_AEID_CQ_OPERATION_ERROR = 0x0203,
+ NES_AEQE_AEID_PRIV_OPERATION_DENIED = 0x0204,
+ NES_AEQE_AEID_RDMA_READ_WHILE_ORD_ZERO = 0x0205,
+ NES_AEQE_AEID_STAG_ZERO_INVALID = 0x0206,
+ NES_AEQE_AEID_DDP_INVALID_MSN_GAP_IN_MSN = 0x0301,
+ NES_AEQE_AEID_DDP_INVALID_MSN_RANGE_IS_NOT_VALID = 0x0302,
+ NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER = 0x0303,
+ NES_AEQE_AEID_DDP_UBE_INVALID_DDP_VERSION = 0x0304,
+ NES_AEQE_AEID_DDP_UBE_INVALID_MO = 0x0305,
+ NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE = 0x0306,
+ NES_AEQE_AEID_DDP_UBE_INVALID_QN = 0x0307,
+ NES_AEQE_AEID_DDP_NO_L_BIT = 0x0308,
+ NES_AEQE_AEID_RDMAP_ROE_INVALID_RDMAP_VERSION = 0x0311,
+ NES_AEQE_AEID_RDMAP_ROE_UNEXPECTED_OPCODE = 0x0312,
+ NES_AEQE_AEID_ROE_INVALID_RDMA_READ_REQUEST = 0x0313,
+ NES_AEQE_AEID_ROE_INVALID_RDMA_WRITE_OR_READ_RESP = 0x0314,
+ NES_AEQE_AEID_INVALID_ARP_ENTRY = 0x0401,
+ NES_AEQE_AEID_INVALID_TCP_OPTION_RCVD = 0x0402,
+ NES_AEQE_AEID_STALE_ARP_ENTRY = 0x0403,
+ NES_AEQE_AEID_LLP_CLOSE_COMPLETE = 0x0501,
+ NES_AEQE_AEID_LLP_CONNECTION_RESET = 0x0502,
+ NES_AEQE_AEID_LLP_FIN_RECEIVED = 0x0503,
+ NES_AEQE_AEID_LLP_RECEIVED_MARKER_AND_LENGTH_FIELDS_DONT_MATCH = 0x0504,
+ NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR = 0x0505,
+ NES_AEQE_AEID_LLP_SEGMENT_TOO_LARGE = 0x0506,
+ NES_AEQE_AEID_LLP_SEGMENT_TOO_SMALL = 0x0507,
+ NES_AEQE_AEID_LLP_SYN_RECEIVED = 0x0508,
+ NES_AEQE_AEID_LLP_TERMINATE_RECEIVED = 0x0509,
+ NES_AEQE_AEID_LLP_TOO_MANY_RETRIES = 0x050a,
+ NES_AEQE_AEID_LLP_TOO_MANY_KEEPALIVE_RETRIES = 0x050b,
+ NES_AEQE_AEID_RESET_SENT = 0x0601,
+ NES_AEQE_AEID_TERMINATE_SENT = 0x0602,
+ NES_AEQE_AEID_DDP_LCE_LOCAL_CATASTROPHIC = 0x0700
+};
+
+enum nes_iwarp_sq_opcodes {
+ NES_IWARP_SQ_WQE_WRPDU = (1<<15),
+ NES_IWARP_SQ_WQE_PSH = (1<<21),
+ NES_IWARP_SQ_WQE_STREAMING = (1<<23),
+ NES_IWARP_SQ_WQE_IMM_DATA = (1<<28),
+ NES_IWARP_SQ_WQE_READ_FENCE = (1<<29),
+ NES_IWARP_SQ_WQE_LOCAL_FENCE = (1<<30),
+ NES_IWARP_SQ_WQE_SIGNALED_COMPL = (1<<31),
+};
+
+enum nes_iwarp_sq_wqe_bits {
+ NES_IWARP_SQ_OP_RDMAW = 0,
+ NES_IWARP_SQ_OP_RDMAR = 1,
+ NES_IWARP_SQ_OP_SEND = 3,
+ NES_IWARP_SQ_OP_SENDINV = 4,
+ NES_IWARP_SQ_OP_SENDSE = 5,
+ NES_IWARP_SQ_OP_SENDSEINV = 6,
+ NES_IWARP_SQ_OP_BIND = 8,
+ NES_IWARP_SQ_OP_FAST_REG = 9,
+ NES_IWARP_SQ_OP_LOCINV = 10,
+ NES_IWARP_SQ_OP_RDMAR_LOCINV = 11,
+ NES_IWARP_SQ_OP_NOP = 12,
+};
+
+#define NES_EEPROM_READ_REQUEST (1<<16)
+#define NES_MAC_ADDR_VALID (1<<20)
+
+/*
+ * NES index registers init values.
+ */
+struct nes_init_values {
+ u32 index;
+ u32 data;
+ u8 wrt;
+};
+
+/*
+ * NES registers in BAR0.
+ */
+struct nes_pci_regs {
+ u32 int_status;
+ u32 int_mask;
+ u32 int_pending;
+ u32 intf_int_status;
+ u32 intf_int_mask;
+ u32 other_regs[59]; /* pad out to 256 bytes for now */
+};
+
+#define NES_CQP_SQ_SIZE 128
+#define NES_CCQ_SIZE 128
+#define NES_NIC_WQ_SIZE 512
+#define NES_NIC_CTX_SIZE ((NES_NIC_CTX_RQ_SIZE_512) | (NES_NIC_CTX_SQ_SIZE_512))
+#define NES_NIC_BACK_STORE 0x00038000
+
+struct nes_device;
+
+struct nes_hw_nic_qp_context {
+ __le32 context_words[6];
+};
+
+struct nes_hw_nic_sq_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_rq_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_nic_cqe {
+ __le32 cqe_words[4];
+};
+
+struct nes_hw_cqp_qp_context {
+ __le32 context_words[4];
+};
+
+struct nes_hw_cqp_wqe {
+ __le32 wqe_words[16];
+};
+
+struct nes_hw_qp_wqe {
+ __le32 wqe_words[32];
+};
+
+struct nes_hw_cqe {
+ __le32 cqe_words[8];
+};
+
+struct nes_hw_ceqe {
+ __le32 ceqe_words[2];
+};
+
+struct nes_hw_aeqe {
+ __le32 aeqe_words[4];
+};
+
+struct nes_cqp_request {
+ wait_queue_head_t waitq;
+ struct nes_hw_cqp_wqe cqp_wqe;
+ struct list_head list;
+ atomic_t refcount;
+ u16 major_code;
+ u16 minor_code;
+ u8 waiting;
+ u8 request_done;
+ u8 padding[2];
+};
+
+struct nes_hw_cqp {
+ struct nes_hw_cqp_wqe *sq_vbase;
+ dma_addr_t sq_pbase;
+ spinlock_t lock;
+ wait_queue_head_t waitq;
+ u16 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+};
+
+#define NES_FIRST_FRAG_SIZE 128
+struct nes_first_frag {
+ u8 buffer[NES_FIRST_FRAG_SIZE];
+};
+
+struct nes_hw_nic {
+ struct nes_first_frag *first_frag_vbase; /* virtual address of first frags */
+ struct nes_hw_nic_sq_wqe *sq_vbase; /* virtual address of sq */
+ struct nes_hw_nic_rq_wqe *rq_vbase; /* virtual address of rq */
+ struct sk_buff *tx_skb[NES_NIC_WQ_SIZE];
+ struct sk_buff *rx_skb[NES_NIC_WQ_SIZE];
+ dma_addr_t frag_paddr[NES_NIC_WQ_SIZE];
+ dma_addr_t sq_pbase; /* PCI memory for host rings */
+ dma_addr_t rq_pbase; /* PCI memory for host rings */
+
+ u16 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+ u16 rq_head;
+ u16 rq_tail;
+ u16 rq_size;
+
+ spinlock_t sq_lock;
+};
+
+struct nes_hw_nic_cq {
+ struct nes_hw_nic_cqe volatile *cq_vbase; /* PCI memory for host rings */
+ void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
+ dma_addr_t cq_pbase; /* PCI memory for host rings */
+ u16 cq_head;
+ u16 cq_size;
+ u16 cq_number;
+};
+
+struct nes_hw_qp {
+ struct nes_hw_qp_wqe *sq_vbase; /* PCI memory for host rings */
+ struct nes_hw_qp_wqe *rq_vbase; /* PCI memory for host rings */
+ void *q2_vbase; /* PCI memory for host rings */
+ dma_addr_t sq_pbase; /* PCI memory for host rings */
+ dma_addr_t rq_pbase; /* PCI memory for host rings */
+ dma_addr_t q2_pbase; /* PCI memory for host rings */
+ u32 qp_id;
+ u16 sq_head;
+ u16 sq_tail;
+ u16 sq_size;
+ u16 rq_head;
+ u16 rq_tail;
+ u16 rq_size;
+ u8 rq_encoded_size;
+ u8 sq_encoded_size;
+};
+
+struct nes_hw_cq {
+ struct nes_hw_cqe volatile *cq_vbase; /* PCI memory for host rings */
+ void (*ce_handler)(struct nes_device *nesdev, struct nes_hw_cq *cq);
+ dma_addr_t cq_pbase; /* PCI memory for host rings */
+ u16 cq_head;
+ u16 cq_size;
+ u16 cq_number;
+};
+
+struct nes_hw_ceq {
+ struct nes_hw_ceqe volatile *ceq_vbase; /* PCI memory for host rings */
+ dma_addr_t ceq_pbase; /* PCI memory for host rings */
+ u16 ceq_head;
+ u16 ceq_size;
+};
+
+struct nes_hw_aeq {
+ struct nes_hw_aeqe volatile *aeq_vbase; /* PCI memory for host rings */
+ dma_addr_t aeq_pbase; /* PCI memory for host rings */
+ u16 aeq_head;
+ u16 aeq_size;
+};
+
+struct nic_qp_map {
+ u8 qpid;
+ u8 nic_index;
+ u8 logical_port;
+ u8 is_hnic;
+};
+
+#define NES_CQP_ARP_AEQ_INDEX_MASK 0x000f0000
+#define NES_CQP_ARP_AEQ_INDEX_SHIFT 16
+
+#define NES_CQP_APBVT_ADD 0x00008000
+#define NES_CQP_APBVT_NIC_SHIFT 16
+
+#define NES_ARP_ADD 1
+#define NES_ARP_DELETE 2
+#define NES_ARP_RESOLVE 3
+
+#define NES_MAC_SW_IDLE 0
+#define NES_MAC_SW_INTERRUPT 1
+#define NES_MAC_SW_MH 2
+
+struct nes_arp_entry {
+ u32 ip_addr;
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct nes_adapter {
+ u32 hw_rev;
+ u64 fw_ver;
+
+ u32 vendor_id;
+ u32 vendor_part_id;
+ struct nes_qp **qp_table;
+ u32 device_cap_flags;
+ u32 tick_delta;
+ u32 timer_int_req;
+ /* RNIC Resource Lists */
+ unsigned long *allocated_qps;
+ unsigned long *allocated_cqs;
+ unsigned long *allocated_mrs;
+ unsigned long *allocated_pds;
+ struct list_head active_listeners;
+ spinlock_t resource_lock;
+ spinlock_t phy_lock;
+
+ /* arp table */
+ unsigned long *allocated_arps;
+ struct nes_arp_entry arp_table[NES_MAX_ARP_TABLE_SIZE];
+ u32 arp_table_size;
+ u32 next_arp_index;
+
+ /* Adapter CEQ and AEQs */
+ struct nes_hw_ceq ceq[16];
+ struct nes_hw_aeq aeq[8];
+
+ /* RNIC Limits */
+ u32 max_mr;
+ u32 max_256pbl;
+ u32 max_4kpbl;
+ u32 free_256pbl;
+ u32 free_4kpbl;
+ u32 max_mr_size;
+ u32 max_qp;
+ u32 next_qp;
+ u32 max_irrq;
+ u32 max_qp_wr;
+ u32 max_sge;
+ u32 max_cq;
+ u32 next_cq;
+ u32 max_cqe;
+ u32 max_pd;
+ u32 base_pd;
+ u32 next_pd;
+ u32 hte_index_mask;
+
+ /* EEPROM information */
+ u32 rx_pool_size;
+ u32 tx_pool_size;
+ u32 rx_threshold;
+ u32 tcp_timer_core_clk_divisor;
+ u32 iwarp_config;
+ u32 cm_config;
+ u32 sws_timer_config;
+ u32 tcp_config1;
+ u32 wqm_wat;
+ u32 core_clock;
+ u32 firmware_version;
+
+ u32 nic_rx_eth_route_err;
+
+ /* Adapter base MAC address */
+ u16 mac_addr_high;
+ u32 mac_addr_low;
+
+ u16 firmware_eeprom_offset;
+ u16 software_eeprom_offset;
+
+ u16 max_irrq_wr;
+
+ /* PCI information */
+ unsigned int devfn;
+ unsigned char bus_number;
+ unsigned char OneG_Mode;
+
+ struct list_head list;
+ /* list of the netdev's associated with each logical port */
+ struct list_head nesvnic_list[4];
+
+ unsigned char ref_count;
+ u8 netdev_count;
+ u8 netdev_max; /* from host nic address count in EEPROM */
+ u8 port_count;
+
+ /* the phy index for each port */
+ u8 phy_index[4];
+ u8 mac_sw_state[4];
+ u8 mac_link_down[4];
+ u8 ports[4];
+
+ struct timer_list mh_timer;
+ /* wait_queue_head_t wait_q; */
+ struct work_struct work;
+ struct workqueue_struct *work_q;
+ /* u32 worker_quit; */
+
+ void *cm_context;
+};
+
+struct nes_pbl {
+ u64 *pbl_vbase;
+ dma_addr_t pbl_pbase;
+ unsigned long user_base;
+ u32 pbl_size;
+ struct list_head list;
+ /* TODO: need to add list for two level tables */
+};
+
+struct nes_listener {
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ struct nes_vnic *nesvnic;
+ struct iw_cm_id *cm_id;
+ struct list_head list;
+ unsigned long socket;
+ struct socket *ksock;
+ u8 accept_failed;
+};
+
+struct nes_ib_device;
+
+struct nes_vnic {
+ struct nes_ib_device *nesibdev;
+ u64 sq_full;
+ u64 sq_locked;
+ u64 tso_requests;
+ u64 segmented_tso_requests;
+ u64 linearized_skbs;
+ u64 tx_sw_dropped;
+ u64 endnode_nstat_rx_discard;
+ u64 endnode_nstat_rx_octets;
+ u64 endnode_nstat_rx_frames;
+ u64 endnode_nstat_tx_octets;
+ u64 endnode_nstat_tx_frames;
+ u64 endnode_ipv4_tcp_retransmits;
+ /* void *mem; */
+ struct nes_device *nesdev;
+ struct net_device *netdev;
+ struct vlan_group *vlan_grp;
+ int budget;
+ int rx_cqes_completed;
+ int cqe_allocs_pending;
+ u32 msg_enable;
+ /* u32 tx_avail; */
+ __be32 local_ipaddr;
+
+ spinlock_t tx_lock; /* could use netdev tx lock? */
+ u32 nic_mem_size;
+ void *nic_vbase;
+ dma_addr_t nic_pbase;
+ struct nes_hw_nic nic;
+ struct nes_hw_nic_cq nic_cq;
+
+ struct net_device_stats netstats;
+ /* used to put the netdev on the adapters logical port list */
+ struct list_head list;
+ u16 max_frame_size;
+ u8 netdev_open;
+ u8 linkup;
+ u8 logical_port;
+ u8 netdev_index; /* might not be needed, indexes nesdev->netdev */
+ u8 perfect_filter_index;
+ u8 nic_index;
+ u8 qp_nic_index[4];
+ u8 next_qp_nic_index;
+ u8 of_device_registered;
+ u8 rdma_enabled;
+ u8 cqes_pending;
+ u8 rx_checksum_disabled;
+};
+
+struct nes_ib_device {
+ struct ib_device ibdev;
+ struct nes_vnic *nesvnic;
+
+ /* Virtual RNIC Limits */
+ u32 max_mr;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_pd;
+ u32 num_mr;
+ u32 num_qp;
+ u32 num_cq;
+ u32 num_pd;
+};
+
+#endif /* __NES_HW_H */
+
^ permalink raw reply
* Re: [PATCH 2/14] nes: device structures and defines
From: Jeff Garzik @ 2007-08-08 1:13 UTC (permalink / raw)
To: ggrundstrom; +Cc: rdreier, ewg, netdev
In-Reply-To: <200708080045.l780jE9E004667@neteffect.com>
ggrundstrom@neteffect.com wrote:
> +#ifndef PCI_VENDOR_ID_NETEFFECT /* not in pci.ids yet */
> +#define PCI_VENDOR_ID_NETEFFECT 0x1678
this should be part of your patch
> +#define PCI_DEVICE_ID_NETEFFECT_NE020 0x0100
no need for a #define at all, just use the hex number if the ONLY place
its used is in the pci_device_id table.
Doing so avoids patch hell that is pci_ids.h, avoids adding a constant
for a single-use hex number that's arbitrary anyway
> +#define BAR_0 0
> +#define BAR_1 2
delete
> +#define RX_BUF_SIZE (1536 + 8)
this number was blindly copied from another driver, right?
> +#ifdef NES_DEBUG
> +#define assert(expr) \
> +if(!(expr)) { \
> + printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n", \
> + #expr, __FILE__, __FUNCTION__, __LINE__); \
> +}
> +#ifndef dprintk
> +#define dprintk(fmt, args...) do { printk(KERN_ERR PFX fmt, ##args); } while (0)
> +#endif
look around, we already have debug macros. you're probably copying from
an older net driver that doesn't yet use the new stuff
> +#define NES_EVENT_TIMEOUT 1200000
> +/* #define NES_EVENT_TIMEOUT 1200 */
> +#else
> +#define assert(expr) do {} while (0)
> +#define dprintk(fmt, args...) do {} while (0)
> +
> +#define NES_EVENT_TIMEOUT 100000
> +#endif
> +
> +#include "nes_hw.h"
> +#include "nes_verbs.h"
> +#include "nes_context.h"
> +#include "nes_user.h"
> +#include "nes_cm.h"
> +
> +
> +extern unsigned int nes_drv_opt;
> +extern unsigned int nes_debug_level;
> +
> +extern struct list_head nes_adapter_list;
> +extern struct list_head nes_dev_list;
> +
> +extern int max_mtu;
> +#define max_frame_len (max_mtu+ETH_HLEN)
> +extern int interrupt_mod_interval;
> +
> +struct nes_device {
> + struct nes_adapter *nesadapter;
> + void __iomem *regs;
> + void __iomem *index_reg;
> + struct pci_dev *pcidev;
> + struct net_device *netdev[NES_NIC_MAX_NICS];
this is questionable. why do you need multiple netdevs? multiple
ports? ok. multiple queues? not ok. see recent netdev discussions.
> + u64 link_status_interrupts;
> + struct tasklet_struct dpc_tasklet;
> + spinlock_t indexed_regs_lock;
> + unsigned long doorbell_start;
> + unsigned long csr_start;
> + unsigned long mac_tx_errors;
> + unsigned long mac_pause_frames_sent;
> + unsigned long mac_pause_frames_received;
> + unsigned long mac_rx_errors;
> + unsigned long mac_rx_crc_errors;
> + unsigned long mac_rx_symbol_err_frames;
> + unsigned long mac_rx_jabber_frames;
> + unsigned long mac_rx_oversized_frames;
> + unsigned long mac_rx_short_frames;
> + unsigned int mac_index;
> + unsigned int nes_stack_start;
> +
> + /* Control Structures */
> + void *cqp_vbase;
> + dma_addr_t cqp_pbase;
> + u32 cqp_mem_size;
> + u8 ceq_index;
> + u8 nic_ceq_index;
> + struct nes_hw_cqp cqp;
> + struct nes_hw_cq ccq;
> + struct list_head cqp_avail_reqs;
> + struct list_head cqp_pending_reqs;
> + struct nes_cqp_request *nes_cqp_requests;
> +
> + u32 int_req;
> + u32 int_stat;
> + u32 timer_int_req;
> + u32 timer_only_int_count;
> + u32 intf_int_req;
> + u32 et_rx_coalesce_usecs_irq;
> + struct list_head list;
> +
> + u16 base_doorbell_index;
> + u8 msi_enabled;
> + u8 netdev_count;
> + u8 napi_isr_ran;
> + u8 disable_rx_flow_control;
> + u8 disable_tx_flow_control;
#1: please consider using tabs to separate type and name, which makes
the struct definition far easier to read.
See drivers/net/tg3.h for an example
#2: consider putting all RX-related items together, and all TX-related
items together. this makes cacheline sharing more likely.
> +/* Linux kernel version interface changes */
> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
> +static inline unsigned short nes_skb_lso_size(const struct sk_buff *skb)
> +{
> + return(skb_shinfo(skb)->tso_size);
> +}
> +#define nes_skb_linearize(_skb, _type) skb_linearize(_skb, _type)
> +#define NES_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func)
> +#else
> +static inline unsigned short nes_skb_lso_size(const struct sk_buff *skb)
> +{
> + return(skb_shinfo(skb)->gso_size);
> +}
> +#define nes_skb_linearize(_skb, _type) skb_linearize(_skb)
> +#define NES_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func)
> +#endif
delete all old-kernel compat code. not appropriate for upstream submission
> +static inline u32 nes_read32(const void __iomem * addr)
> +{
> + return(le32_to_cpu(readl(addr)));
> +}
> +
> +static inline u16 nes_read16(const void __iomem * addr)
> +{
> + return(le16_to_cpu(readw(addr)));
> +}
> +
> +static inline u8 nes_read8(const void __iomem * addr)
> +{
> + return(readb(addr));
> +}
#1: delete these completely useless wrappers
#2: these wrappers are WRONG anyway. You don't need endian conversion
macros.
> +/* Write to memory-mapped device */
> +static inline void nes_write_indexed(struct nes_device *nesdev, u32 reg_index, u32 val)
> +{
> + unsigned long flags;
> + void __iomem * addr = nesdev->index_reg;
> +
> + spin_lock_irqsave(&nesdev->indexed_regs_lock, flags);
> +
> + /* dprintk("Writing %08X, to indexed offset %08X using address %p and %p.\n",
> + val, reg_index, addr, addr+4); */
> + writel(cpu_to_le32(reg_index), addr);
> + writel(cpu_to_le32(val),(u8 *)addr + 4);
wrong -- endian conversion macros not needed with writel()
> + spin_unlock_irqrestore(&nesdev->indexed_regs_lock, flags);
> +}
> +
> +static inline void nes_write32(void __iomem * addr, u32 val)
> +{
> + /* dprintk("Writing %08X, to address %p.\n", val, addr); */
> + writel(cpu_to_le32(val), addr);
> +}
> +
> +static inline void nes_write16(void __iomem * addr, u16 val)
> +{
> + writew(cpu_to_le16(val), addr);
> +}
> +
> +static inline void nes_write8(void __iomem * addr, u8 val)
> +{
> + writeb(val, addr);
> +}
#1: delete wrappers
#2: the wrappers are buggy anyway
> +static inline struct nes_vnic *to_nesvnic(struct ib_device *ibdev) {
> + return (container_of(ibdev, struct nes_ib_device, ibdev)->nesvnic);
> +}
> +
> +static inline struct nes_pd *to_nespd(struct ib_pd *ibpd) {
> + return (container_of(ibpd, struct nes_pd, ibpd));
> +}
> +
> +static inline struct nes_ucontext *to_nesucontext(struct ib_ucontext *ibucontext) {
> + return (container_of(ibucontext, struct nes_ucontext, ibucontext));
> +}
> +
> +static inline struct nes_mr *to_nesmr(struct ib_mr *ibmr) {
> + return (container_of(ibmr, struct nes_mr, ibmr));
> +}
> +
> +static inline struct nes_mr *to_nesmw(struct ib_mw *ibmw) {
> + return (container_of(ibmw, struct nes_mr, ibmw));
> +}
> +
> +static inline struct nes_mr *to_nesfmr(struct ib_fmr *ibfmr) {
> + return (container_of(ibfmr, struct nes_mr, ibfmr));
> +}
> +
> +static inline struct nes_cq *to_nescq(struct ib_cq *ibcq) {
> + return (container_of(ibcq, struct nes_cq, ibcq));
> +}
> +
> +static inline struct nes_qp *to_nesqp(struct ib_qp *ibqp) {
> + return (container_of(ibqp, struct nes_qp, ibqp));
> +}
all functions have their starting brace in column 1, not at EOL
> +/* Utils */
> +#define CRC32C_POLY 0x1EDC6F41
use libcrc32c rather than reinventing the wheel
> +static inline struct nes_cqp_request
> + *nes_get_cqp_request(struct nes_device *nesdev, int holding_lock)
> +{
> + unsigned long flags;
> + struct nes_cqp_request *cqp_request = NULL;
> +
> + if (!holding_lock) {
> + spin_lock_irqsave(&nesdev->cqp.lock, flags);
> + }
> + if (!list_empty(&nesdev->cqp_avail_reqs)) {
> + cqp_request = list_entry(nesdev->cqp_avail_reqs.next,
> + struct nes_cqp_request, list);
> + list_del_init(&cqp_request->list);
> + }
> + if (!holding_lock) {
> + spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
> + }
> +
> + if (cqp_request) {
> + cqp_request->waiting = 0;
> + cqp_request->request_done = 0;
> + init_waitqueue_head(&cqp_request->waitq);
> + /* dprintk("%s: Got cqp request %p from the available list \n",
> + __FUNCTION__, cqp_request); */
> + } else
> + dprintk("%s: CQP request queue is empty.\n", __FUNCTION__);
> +
> + return (cqp_request);
> +}
see below comment about conditional locking
> +static inline void nes_post_cqp_request(struct nes_device *nesdev,
> + struct nes_cqp_request *cqp_request, int holding_lock, int ring_doorbell)
> +{
> + /* caller must be holding CQP lock */
> + struct nes_hw_cqp_wqe *cqp_wqe;
> + unsigned long flags;
> + u32 cqp_head;
> +
> + if (!holding_lock) {
> + spin_lock_irqsave(&nesdev->cqp.lock, flags);
> + }
> +
> + if (((((nesdev->cqp.sq_tail+(nesdev->cqp.sq_size*2))-nesdev->cqp.sq_head) &
> + (nesdev->cqp.sq_size - 1)) != 1)
> + && (list_empty(&nesdev->cqp_pending_reqs))) {
> + cqp_head = nesdev->cqp.sq_head++;
> + nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
> + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
> + memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
> + barrier();
> + *((struct nes_cqp_request **)&cqp_wqe->wqe_words
> + [NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]) = cqp_request;
> + dprintk("%s: CQP request (opcode 0x%02X), line 1 = 0x%08X put on CQPs SQ,"
> + " request = %p, cqp_head = %u, cqp_tail = %u, cqp_size = %u,"
> + " waiting = %d, refcount = %d.\n",
> + __FUNCTION__, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]&0x3f,
> + cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX], cqp_request,
> + nesdev->cqp.sq_head, nesdev->cqp.sq_tail, nesdev->cqp.sq_size,
> + cqp_request->waiting, atomic_read(&cqp_request->refcount));
> + } else {
> + dprintk("%s: CQP request %p (opcode 0x%02X), line 1 = 0x%08X"
> + " put on the pending queue.\n",
> + __FUNCTION__, cqp_request,
> + cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]&0x3f,
> + cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_ID_IDX]);
> + list_add_tail(&cqp_request->list, &nesdev->cqp_pending_reqs);
> + }
> +
> + if (ring_doorbell) {
> + barrier();
> + /* Ring doorbell (1 WQEs) */
> + nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
> + }
> +
> + if (!holding_lock) {
> + spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
> + }
> +
> + return;
> +}
#1: these two are way too big to inline
#2: conditional locking has proven to be fragile. don't do it. create
a wrapper function that acquires/releases the lock, and an inner
function that does the real work.
^ permalink raw reply
* [PATCH 6/14] nes: hardware init
From: ggrundstrom @ 2007-08-08 1:05 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
Hardware initialization and interrupt processing
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_hw.c
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_hw.c 2007-08-06 20:09:04.000000000 -0500
@@ -0,0 +1,2653 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+*
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_vlan.h>
+
+
+#include "nes.h"
+u32 crit_err_count = 0;
+
+#include "nes_cm.h"
+
+
+#ifdef NES_DEBUG
+static unsigned char *nes_iwarp_state_str[] = {
+ "Non-Existant",
+ "Idle",
+ "RTS",
+ "Closing",
+ "RSVD1",
+ "Terminate",
+ "Error",
+ "RSVD2",
+};
+
+static unsigned char *nes_tcp_state_str[] = {
+ "Non-Existant",
+ "Closed",
+ "Listen",
+ "SYN Sent",
+ "SYN Rcvd",
+ "Established",
+ "Close Wait",
+ "FIN Wait 1",
+ "Closing",
+ "Last Ack",
+ "FIN Wait 2",
+ "Time Wait",
+ "RSVD1",
+ "RSVD2",
+ "RSVD3",
+ "RSVD4",
+};
+#endif
+
+/**
+ * nes_init_adapter - initialize adapter
+ */
+struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
+ struct nes_adapter *nesadapter = NULL;
+ unsigned long num_pds;
+ u32 u32temp;
+ u32 port_count;
+ u16 max_rq_wrs;
+ u16 max_sq_wrs;
+ u32 max_mr;
+ u32 max_256pbl;
+ u32 max_4kpbl;
+ u32 max_qp;
+ u32 max_irrq;
+ u32 max_cq;
+ u32 hte_index_mask;
+ u32 adapter_size;
+ u32 arp_table_size;
+ u8 OneG_Mode;
+
+ /* search the list of existing adapters */
+ list_for_each_entry(nesadapter, &nes_adapter_list, list) {
+ dprintk("Searching Adapter list for PCI devfn = 0x%X,"
+ " adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
+ nesdev->pcidev->devfn,
+ PCI_SLOT(nesadapter->devfn),
+ nesadapter->bus_number,
+ PCI_SLOT(nesdev->pcidev->devfn),
+ nesdev->pcidev->bus->number );
+ if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
+ (nesadapter->bus_number == nesdev->pcidev->bus->number)) {
+ nesadapter->ref_count++;
+ return(nesadapter);
+ }
+ }
+
+ /* no adapter found */
+ num_pds = pci_resource_len(nesdev->pcidev, BAR_1) / 4096;
+ if (hw_rev != NE020_REV) {
+ dprintk("%s: NE020 driver detected unknown hardware revision 0x%x\n",
+ __FUNCTION__, hw_rev);
+ return(NULL);
+ }
+
+ dprintk("%s:%u Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
+ __FUNCTION__, __LINE__,
+ nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
+ nes_read_indexed(nesdev, 0x00A4),
+ nes_read_indexed(nesdev, 0x00A8));
+
+ dprintk("%s: Reset and init NE020\n", __FUNCTION__);
+ if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0) {
+ return(NULL);
+ }
+ if (nes_init_serdes(nesdev, port_count)) {
+ return(NULL);
+ }
+ nes_init_csr_ne020(nesdev, hw_rev, port_count);
+
+ /* Setup and enable the periodic timer */
+ nesdev->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
+ if (nesdev->et_rx_coalesce_usecs_irq) {
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
+ ((u32)(nesdev->et_rx_coalesce_usecs_irq * 8)));
+ } else {
+ nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
+ }
+
+ max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
+ dprintk("%s: QP_CTX_SIZE=%u\n", __FUNCTION__, max_qp);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
+ if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
+ dprintk("Reducing Max QPs to %u due to hash table size = 0x%08X\n",
+ max_qp, u32temp);
+ max_qp = (u32)1 << (u32temp & 0x001f);
+ }
+
+ hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
+ dprintk("Max QP = %u, hte_index_mask = 0x%08X.\n", max_qp, hte_index_mask);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
+
+ max_irrq = 1 << (u32temp & 0x001f);
+
+ if (max_qp > max_irrq) {
+ max_qp = max_irrq;
+ dprintk("Reducing Max QPs to %u due to Available Q1s.\n", max_qp);
+ }
+
+ /* there should be no reason to allocate more pds than qps */
+ if (num_pds > max_qp)
+ num_pds = max_qp;
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
+ max_mr = (u32)8192 << (u32temp & 0x7);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
+ max_256pbl = (u32)1 << (u32temp & 0x0000001f);
+ max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
+ max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
+ arp_table_size = 1 << u32temp;
+
+ adapter_size = (sizeof(struct nes_adapter) +
+ (sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
+ adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
+ adapter_size += sizeof(struct nes_qp **) * max_qp;
+
+ /* allocate a new adapter struct */
+ nesadapter = kmalloc(adapter_size, GFP_KERNEL);
+ if (nesadapter == NULL) {
+ return(NULL);
+ }
+ memset(nesadapter, 0, adapter_size);
+ dprintk("Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
+ nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
+
+ /* populate the new nesadapter */
+ nesadapter->devfn = nesdev->pcidev->devfn;
+ nesadapter->bus_number = nesdev->pcidev->bus->number;
+ nesadapter->ref_count = 1;
+ nesadapter->timer_int_req = 0xffff0000;
+ nesadapter->OneG_Mode = OneG_Mode;
+
+ /* nesadapter->tick_delta = clk_divisor; */
+ nesadapter->hw_rev = hw_rev;
+ nesadapter->port_count = port_count;
+
+ nesadapter->max_qp = max_qp;
+ nesadapter->hte_index_mask = hte_index_mask;
+ nesadapter->max_irrq = max_irrq;
+ nesadapter->max_mr = max_mr;
+ nesadapter->max_256pbl = max_256pbl - 1;
+ nesadapter->max_4kpbl = max_4kpbl - 1;
+ nesadapter->max_cq = max_cq;
+ nesadapter->free_256pbl = max_256pbl - 1;
+ nesadapter->free_4kpbl = max_4kpbl - 1;
+ nesadapter->max_pd = num_pds;
+ nesadapter->arp_table_size = arp_table_size;
+ nesadapter->base_pd = 1;
+
+ nesadapter->device_cap_flags =
+ IB_DEVICE_ZERO_STAG | IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW;
+
+ nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
+ [(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
+ nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
+ nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
+ nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
+ nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
+ nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
+
+
+ /* mark the usual suspect QPs and CQs as in use */
+ for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
+ set_bit(u32temp, nesadapter->allocated_qps);
+ set_bit(u32temp, nesadapter->allocated_cqs);
+ }
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
+
+ max_rq_wrs = ((u32temp >> 8) & 3);
+ switch (max_rq_wrs) {
+ case 0:
+ max_rq_wrs = 4;
+ break;
+ case 1:
+ max_rq_wrs = 16;
+ break;
+ case 2:
+ max_rq_wrs = 32;
+ break;
+ case 3:
+ max_rq_wrs = 512;
+ break;
+ }
+
+ max_sq_wrs = (u32temp & 3);
+ switch (max_sq_wrs) {
+ case 0:
+ max_sq_wrs = 4;
+ break;
+ case 1:
+ max_sq_wrs = 16;
+ break;
+ case 2:
+ max_sq_wrs = 32;
+ break;
+ case 3:
+ max_sq_wrs = 512;
+ break;
+ }
+ nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
+ dprintk("Max wqes = %u.\n", nesadapter->max_qp_wr);
+
+ nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
+ dprintk("%s: Max IRRQ wqes = %u.\n", __FUNCTION__, nesadapter->max_irrq_wr);
+
+
+ nesadapter->max_sge = 4;
+ nesadapter->max_cqe = 32767;
+
+ if (nes_read_eeprom_values(nesdev, nesadapter)) {
+ printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
+ kfree(nesadapter);
+ return(NULL);
+ }
+
+ u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
+ nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
+ (u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
+ dprintk("%s: TCP Timer Config0=%08x\n", __FUNCTION__,
+ nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG));
+
+ /* setup port configuration */
+ if (nesadapter->port_count == 1) {
+ u32temp = 0x00000000;
+ if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT) {
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
+ } else {
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+ }
+ } else {
+ if (nesadapter->port_count == 2) {
+ u32temp = 0x00000044;
+ } else {
+ u32temp = 0x000000e4;
+ }
+ nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
+ }
+
+ nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
+ dprintk("%s: Probe time, LOG2PHY=%u\n", __FUNCTION__,
+ nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
+
+ spin_lock_init(&nesadapter->resource_lock);
+ spin_lock_init(&nesadapter->phy_lock);
+
+ init_timer(&nesadapter->mh_timer);
+ nesadapter->mh_timer.function = nes_mh_fix;
+ nesadapter->mh_timer.expires = jiffies + (HZ/5); /* 1 second */
+ nesadapter->mh_timer.data = (unsigned long)nesdev;
+ add_timer(&nesadapter->mh_timer);
+
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
+ INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
+
+ list_add_tail(&nesadapter->list, &nes_adapter_list);
+
+ return(nesadapter);
+}
+
+
+/**
+ * nes_reset_adapter_ne020
+ */
+unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
+{
+ u32 port_count;
+ u32 u32temp;
+ u32 i;
+
+ u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
+ port_count = ((u32temp & 0x00000300) >> 8) + 1;
+ /* TODO: assuming that both SERDES are set the same for now */
+ *OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
+ dprintk("%s: Initial Software Reset = 0x%08X, port_count=%u\n", __FUNCTION__, u32temp, port_count);
+ if (*OneG_Mode) {
+ dprintk("%s: Running in 1G mode.\n", __FUNCTION__);
+ }
+ u32temp &= 0xff00ffc0;
+ switch (port_count) {
+ case 1:
+ u32temp |= 0x00ee0000;
+ break;
+ case 2:
+ u32temp |= 0x00cc0000;
+ break;
+ case 4:
+ u32temp |= 0x00000000;
+ break;
+ default:
+ return (0);
+ break;
+ }
+
+ /* check and do full reset if needed */
+ if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
+ dprintk("Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000) {
+ mdelay(1);
+ }
+ if (i >= 10000) {
+ dprintk("Did not see full soft reset done.\n");
+ return (0);
+ }
+ }
+
+ /* port reset */
+ switch (port_count) {
+ case 1:
+ u32temp |= 0x00ee0010;
+ break;
+ case 2:
+ u32temp |= 0x00cc0030;
+ break;
+ case 4:
+ u32temp |= 0x00000030;
+ break;
+ }
+
+ dprintk("Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
+ nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000) {
+ mdelay(1);
+ }
+ if (i >= 10000) {
+ dprintk("Did not see port soft reset done.\n");
+ return (0);
+ }
+
+ /* serdes 0 */
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000) {
+ mdelay(1);
+ }
+ if (i >= 5000) {
+ dprintk("Serdes 0 not ready, status=%x\n", u32temp);
+ return (0);
+ }
+
+ /* serdes 1 */
+ if (port_count > 1) {
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000) {
+ mdelay(1);
+ }
+ if (i >= 5000) {
+ dprintk("Serdes 1 not ready, status=%x\n", u32temp);
+ return (0);
+ }
+ }
+
+ i = 0;
+ while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000) {
+ mdelay(1);
+ }
+ dprintk("%s:%u CPU_STATUS loops=%u\n", __FUNCTION__, __LINE__, i);
+ if (i >= 10000) {
+ printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
+ nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
+ return (0);
+ }
+
+ return (port_count);
+}
+
+
+/**
+ * nes_init_serdes
+ */
+int nes_init_serdes(struct nes_device *nesdev, u8 port_count)
+{
+ int i;
+ u32 u32temp;
+
+ /* init serdes 0 */
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
+ & 0x0000000f)) != 0x0000000f) && i++ < 5000) {
+ mdelay(1);
+ }
+ if (i >= 5000) {
+ dprintk("Init: serdes 0 not ready, status=%x\n", u32temp);
+ return (1);
+ }
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0002222);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
+
+ if (port_count > 1) {
+ /* init serdes 1 */
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
+ i = 0;
+ while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1) & 0x0000000f)) != 0x0000000f) &&
+ (i++ < 5000)) {
+ mdelay(1);
+ }
+ if (i >= 5000) {
+ printk("%s: Init: serdes 1 not ready, status=%x\n", __FUNCTION__, u32temp);
+ /* return 1; */
+ }
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
+ }
+ return (0);
+}
+
+
+/**
+ * nes_init_csr_ne020
+ * Initialize registers for ne020 hardware
+ */
+void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
+{
+
+ nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
+ /* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
+ nes_write_indexed(nesdev, 0x000001E8, 0x00020844);
+ nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
+ /* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
+ nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
+ nes_write_indexed(nesdev, 0x00000600, 0x55555555);
+ nes_write_indexed(nesdev, 0x00000604, 0x55555555);
+
+ /* TODO: move these MAC register settings to NIC bringup */
+ nes_write_indexed(nesdev, 0x00002000, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002004, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
+ if (port_count > 1) {
+ nes_write_indexed(nesdev, 0x00002200, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002204, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
+ }
+ if (port_count > 2) {
+ nes_write_indexed(nesdev, 0x00002400, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002404, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
+
+ nes_write_indexed(nesdev, 0x00002600, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002604, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
+ nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
+ nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
+ nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
+ }
+
+ nes_write_indexed(nesdev, 0x00005000, 0x00018000);
+ /* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
+ nes_write_indexed(nesdev, 0x00005004, 0x00020001);
+ nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
+ nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
+
+ /* TODO: move this to code, get from EEPROM */
+ nes_write_indexed(nesdev, 0x00000900, 0x20000001);
+ nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
+ nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
+
+ nes_write_indexed(nesdev, 0x000001EC, 0x5b2625a0);
+ /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
+
+}
+
+
+/**
+ * nes_destroy_adapter - destroy the adapter structure
+ */
+void nes_destroy_adapter(struct nes_adapter *nesadapter)
+{
+ struct nes_adapter *tmp_adapter;
+
+ list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
+ dprintk("%s: Nes Adapter list entry = 0x%p.\n", __FUNCTION__, tmp_adapter);
+ }
+
+ nesadapter->ref_count--;
+ if (!nesadapter->ref_count) {
+ del_timer(&nesadapter->mh_timer);
+
+ dprintk("nes_destroy_adapter: Deleting adapter from adapter list.\n");
+ list_del(&nesadapter->list);
+ dprintk("nes_destroy_adapter: Freeing adapter structure.\n");
+ kfree(nesadapter);
+ }
+ dprintk("%s: Done.\n", __FUNCTION__);
+}
+
+
+/**
+ * nes_init_cqp
+ */
+int nes_init_cqp(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_hw_cqp_qp_context *cqp_qp_context;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_ceq *ceq;
+ struct nes_hw_ceq *nic_ceq;
+ struct nes_hw_aeq *aeq;
+ void *vmem;
+ dma_addr_t pmem;
+ u32 count=0;
+ u32 cqp_head;
+ u64 u64temp;
+ u32 u32temp;
+
+#define NES_NIC_CEQ_SIZE 8
+/* NICs will be on a separate CQ */
+#define NES_CCEQ_SIZE ((nesadapter->max_cq / nesadapter->port_count) - 32)
+
+ /* allocate CQP memory */
+ /* Need to add max_cq to the aeq size once cq overflow checking is added back */
+ /* SQ is 512 byte aligned, others are 256 byte aligned */
+ nesdev->cqp_mem_size = 512 +
+ (sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
+ (sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
+ max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
+ max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
+ (sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
+ sizeof(struct nes_hw_cqp_qp_context);
+
+ nesdev->cqp_vbase = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ &nesdev->cqp_pbase);
+ if (!nesdev->cqp_vbase) {
+ dprintk(KERN_ERR PFX "Unable to allocate memory for host descriptor rings\n");
+ return(-ENOMEM);
+ }
+ memset(nesdev->cqp_vbase, 0, nesdev->cqp_mem_size);
+
+ /* Allocate a twice the number of CQP requests as the SQ size */
+ nesdev->nes_cqp_requests = kmalloc(sizeof(struct nes_cqp_request) *
+ 2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
+ if (NULL == nesdev->nes_cqp_requests) {
+ dprintk(KERN_ERR PFX "Unable to allocate memory CQP request entries.\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+ nesdev->cqp.sq_pbase);
+ return(-ENOMEM);
+ }
+ memset(nesdev->nes_cqp_requests, 0, sizeof(struct nes_cqp_request) *
+ 2 * NES_CQP_SQ_SIZE);
+ dprintk("Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
+ nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
+
+ spin_lock_init(&nesdev->cqp.lock);
+ init_waitqueue_head(&nesdev->cqp.waitq);
+
+ /* Setup Various Structures */
+ vmem = (void *)(((unsigned long long)nesdev->cqp_vbase + (512 - 1)) &
+ ~(unsigned long long)(512 - 1));
+ pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
+ ~(unsigned long long)(512 - 1));
+
+ nesdev->cqp.sq_vbase = vmem;
+ nesdev->cqp.sq_pbase = pmem;
+ nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
+ nesdev->cqp.sq_head = 0;
+ nesdev->cqp.sq_tail = 0;
+ nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
+ dprintk("CQP at %p (phys = %016lX).\n",
+ nesdev->cqp.sq_vbase, (unsigned long)nesdev->cqp.sq_pbase);
+
+ vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+ pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
+
+ nesdev->ccq.cq_vbase = vmem;
+ nesdev->ccq.cq_pbase = pmem;
+ nesdev->ccq.cq_size = NES_CCQ_SIZE;
+ nesdev->ccq.cq_head = 0;
+ nesdev->ccq.ce_handler = nes_cqp_ce_handler;
+ nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
+ dprintk("CCQ at %p (phys = %016lX).\n",
+ nesdev->ccq.cq_vbase, (unsigned long)nesdev->ccq.cq_pbase);
+
+ vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+ pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
+
+ nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
+ ceq = &nesadapter->ceq[nesdev->ceq_index];
+ ceq->ceq_vbase = vmem;
+ ceq->ceq_pbase = pmem;
+ ceq->ceq_size = NES_CCEQ_SIZE;
+ ceq->ceq_head = 0;
+ dprintk("CEQ at %p (phys = %016lX).\n",
+ ceq->ceq_vbase, (unsigned long)ceq->ceq_pbase);
+
+ vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+ pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
+
+ nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
+ nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
+ nic_ceq->ceq_vbase = vmem;
+ nic_ceq->ceq_pbase = pmem;
+ nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
+ nic_ceq->ceq_head = 0;
+ dprintk("NIC CEQ at %p (phys = %016lX).\n",
+ nic_ceq->ceq_vbase, (unsigned long)nic_ceq->ceq_pbase);
+
+ vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+ pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
+
+ aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
+ aeq->aeq_vbase = vmem;
+ aeq->aeq_pbase = pmem;
+ aeq->aeq_size = nesadapter->max_qp;
+ aeq->aeq_head = 0;
+ dprintk("AEQ at %p (phys = %016lX).\n",
+ aeq->aeq_vbase, (unsigned long)aeq->aeq_pbase);
+
+ /* Setup QP Context */
+ vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+ pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
+
+ cqp_qp_context = vmem;
+ cqp_qp_context->context_words[0] = (PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10);
+ cqp_qp_context->context_words[1] = 0;
+ cqp_qp_context->context_words[2] = (u32)nesdev->cqp.sq_pbase;
+ cqp_qp_context->context_words[3] = ((u64)nesdev->cqp.sq_pbase) >> 32;
+
+ dprintk("Address of CQP Context = %p.\n", cqp_qp_context);
+ for (count=0;count<4 ; count++) {
+ dprintk("CQP Context, Line %u = %08X.\n",
+ count, cqp_qp_context->context_words[count]);
+ }
+
+ /* Write the address to Create CQP */
+ if ((sizeof(dma_addr_t) > 4)) {
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ ((u64)pmem) >> 32);
+ } else {
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
+ }
+ nes_write_indexed(nesdev,
+ NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
+ (u32)pmem);
+
+ dprintk("Address of CQP SQ = %p.\n", nesdev->cqp.sq_vbase);
+
+ INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
+ INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
+
+ for (count=0; count<2*NES_CQP_SQ_SIZE; count++) {
+ init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
+ list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
+ /* dprintk("Adding cqp request %p to the available list \n",
+ &nesdev->nes_cqp_requests[count]); */
+ }
+
+ /* Write Create CCQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
+ NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
+ ((u32)nesdev->ceq_index<<16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nesdev->ccq.cq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ /* TODO: the following 2 lines likely have endian issues */
+ *((struct nes_hw_cq **)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) = &nesdev->ccq;
+ *((u64 *)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) >>= 1;
+ dprintk("%s: CQ%u context = 0x%08X:0x%08X.\n", __FUNCTION__, nesdev->ccq.cq_number,
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX],
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]);
+
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+
+ /* Write Create CEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_CEQ +
+ ((u32)nesdev->ceq_index << 8));
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX] = cpu_to_le32(ceq->ceq_size);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ *((struct nes_cqp_request **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]) = NULL;
+ u64temp = (u64)ceq->ceq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ /* Write Create AEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_AEQ +
+ ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
+ cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX] = cpu_to_le32(aeq->aeq_size);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)aeq->aeq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ /* Write Create CEQ WQE */
+ cqp_head = nesdev->cqp.sq_head++;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_CEQ +
+ ((u32)nesdev->nic_ceq_index << 8));
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX] = cpu_to_le32(nic_ceq->ceq_size);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nic_ceq->ceq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ /* Poll until CCQP done */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Error creating CQP\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ nesdev->cqp_vbase, nesdev->cqp_pbase);
+ return(-1);
+ }
+ udelay(10);
+ } while (!(nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
+
+ dprintk("CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ u32temp = 0x04800000;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
+
+ /* wait for the CCQ, CEQ, and AEQ to get created */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+ nesdev->cqp_vbase, nesdev->cqp_pbase);
+ return(-1);
+ }
+ udelay(10);
+ } while (((nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
+
+ /* dump the QP status value */
+ dprintk("QP Status = 0x%08X\n", nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ nesdev->cqp.sq_tail++;
+
+ return (0);
+}
+
+
+/**
+ * nes_destroy_cqp
+ */
+int nes_destroy_cqp(struct nes_device *nesdev)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ u32 count=0;
+ u32 cqp_head;
+ unsigned long flags;
+
+ dprintk("Waiting for CQP work to complete.\n");
+ do {
+ if (count++ > 1000) break;
+ udelay(10);
+ } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
+
+ /* Reset CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
+ nesdev->ccq.cq_number);
+
+ /* Disable device interrupts */
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
+ /* Destroy the AEQ */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
+ ((u32)PCI_FUNC(nesdev->pcidev->devfn)<<8));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ /* Destroy the NIC CEQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+ ((u32)nesdev->nic_ceq_index<<8));
+ /* Destroy the CEQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
+ (nesdev->ceq_index<<8));
+ /* Destroy the CCQ */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32( nesdev->ccq.cq_number ||
+ ((u32)nesdev->ceq_index<<16));
+ /* Destroy CQP */
+ cqp_head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
+ NES_CQP_QP_TYPE_CQP);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
+
+ barrier();
+ /* Ring doorbell (4 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
+
+ /* Wait for the destroy to complete */
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ /* wait for the CCQ, CEQ, and AEQ to get destroyed */
+ count = 0;
+ do {
+ if (count++ > 1000) {
+ printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
+ PCI_FUNC(nesdev->pcidev->devfn));
+ break;
+ }
+ udelay(10);
+ } while (((nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != 0));
+
+ /* dump the QP status value */
+ dprintk("Function%d: QP Status = 0x%08X\n",
+ PCI_FUNC(nesdev->pcidev->devfn),
+ nes_read_indexed(nesdev,
+ NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+ kfree(nesdev->nes_cqp_requests);
+
+ /* Free the control structures */
+ pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
+ nesdev->cqp.sq_pbase);
+
+ return (0);
+}
+
+
+/**
+ * nes_init_phy
+ */
+int nes_init_phy(struct nes_device *nesdev)
+{
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 counter = 0;
+ u32 mac_index = nesdev->mac_index;
+ u16 phy_data;
+
+ if (nesadapter->OneG_Mode) {
+ dprintk("1G PHY, mac_index = %d.\n", mac_index);
+ nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 1 phy address %u = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+
+ nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
+
+ /* Reset the PHY */
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
+ udelay(100);
+ counter = 0;
+ do {
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0 = 0x%X.\n", phy_data);
+ if (counter++ > 100) break;
+ } while (phy_data & 0x8000);
+
+ /* Setting no phy loopback */
+ phy_data &= 0xbfff;
+ phy_data |= 0x1140;
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data);
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x17 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x1e = 0x%X.\n", phy_data);
+
+ /* Setting the interrupt mask */
+ nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x19 = 0x%X.\n", phy_data);
+ nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee);
+
+ nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x19 = 0x%X.\n", phy_data);
+
+ /* turning on flow control */
+ nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x4 = 0x%X.\n", phy_data);
+ nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+ (phy_data & ~(0x03E0)) | 0xc00);
+ /* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
+ phy_data | 0xc00); */
+ nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x4 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x9 = 0x%X.\n", phy_data);
+ /* Clear Half duplex */
+ nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
+ phy_data & ~(0x0100));
+ nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy data from register 0x9 = 0x%X.\n", phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
+ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
+ }
+ return (0);
+}
+
+
+/**
+ * nes_init_nic_qp
+ */
+int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct nes_hw_nic_qp_context *nic_context;
+ struct sk_buff *skb;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ unsigned long flags;
+ void *vmem;
+ dma_addr_t pmem;
+ u64 u64temp;
+ int ret;
+ u32 cqp_head;
+ u32 counter;
+ u32 wqe_count;
+
+ /* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
+ nesvnic->nic_mem_size = 256 +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
+ (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
+ (NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
+ sizeof(struct nes_hw_nic_qp_context);
+
+ nesvnic->nic_vbase = pci_alloc_consistent(nesdev->pcidev, nesvnic->nic_mem_size,
+ &nesvnic->nic_pbase);
+ if (!nesvnic->nic_vbase) {
+ dprintk(KERN_ERR PFX "Unable to allocate memory for NIC host descriptor rings\n");
+ return(-ENOMEM);
+ }
+ memset(nesvnic->nic_vbase, 0, nesvnic->nic_mem_size);
+ dprintk("Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
+ nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
+
+ vmem = (void *)(((unsigned long long)nesvnic->nic_vbase + (256 - 1)) &
+ ~(unsigned long long)(256 - 1));
+ pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
+ ~(unsigned long long)(256 - 1));
+
+ dprintk("%s:%u vmem=%p, pmem=%016lX\n",
+ __FUNCTION__, __LINE__, vmem, (long unsigned int)pmem);
+
+ /* Setup the first Fragment buffers */
+ nesvnic->nic.first_frag_vbase = vmem;
+
+ for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+ nesvnic->nic.frag_paddr[counter] = pmem;
+ pmem += sizeof(struct nes_first_frag);
+ }
+
+ /* setup the SQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
+ dprintk("%s:%u vmem=%p, pmem=%016lX\n",
+ __FUNCTION__, __LINE__, vmem, (long unsigned int)pmem);
+
+ nesvnic->nic.sq_vbase = (void *)vmem;
+ nesvnic->nic.sq_pbase = pmem;
+ nesvnic->nic.sq_head = 0;
+ nesvnic->nic.sq_tail = 0;
+ nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
+ for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
+ nic_sqe = &nesvnic->nic.sq_vbase[counter];
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] = NES_NIC_SQ_WQE_DISABLE_CHKSUM |
+ NES_NIC_SQ_WQE_COMPLETION;
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
+ (u32)NES_FIRST_FRAG_SIZE << 16;
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
+ (u32)nesvnic->nic.frag_paddr[counter];
+ nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
+ (u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32);
+ }
+
+ spin_lock_init(&nesvnic->nic.sq_lock);
+
+ /* setup the RQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+ pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+
+ dprintk("%s:%u vmem=%p, pmem=%016lX\n",
+ __FUNCTION__, __LINE__, vmem, (long unsigned int)pmem);
+
+ nesvnic->nic.rq_vbase = vmem;
+ nesvnic->nic.rq_pbase = pmem;
+ nesvnic->nic.rq_head = 0;
+ nesvnic->nic.rq_tail = 0;
+ nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
+
+ /* setup the CQ */
+ vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+ pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+
+ dprintk("%s:%u vmem=%p, pmem=%016lX\n",
+ __FUNCTION__, __LINE__, vmem, (long unsigned int)pmem);
+
+ nesvnic->nic_cq.cq_vbase = vmem;
+ nesvnic->nic_cq.cq_pbase = pmem;
+ nesvnic->nic_cq.cq_head = 0;
+ nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
+#ifdef NES_NAPI
+ nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
+#else
+ nesvnic->nic_cq.ce_handler = nes_nic_ce_handler;
+#endif
+
+ /* Send CreateCQ request to CQP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_head = nesdev->cqp.sq_head;
+ dprintk("%s:%u Before filling out cqp_wqe, cqp=%p, sq_head=%u, sq_tail=%u, cqp_head=%u\n",
+ __FUNCTION__, __LINE__, &nesdev->cqp, nesdev->cqp.sq_head,
+ nesdev->cqp.sq_tail, cqp_head);
+
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID | (nesvnic->nic_cq.cq_size << 16);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
+ nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nesvnic->nic_cq.cq_pbase;
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
+ /* the following two lines likely have endian issues */
+ *((struct nes_hw_nic_cq **)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) =
+ &nesvnic->nic_cq;
+ *((u64 *)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) >>= 1;
+ dprintk("%s: CQ%u context = 0x%08X:0x%08X.\n", __FUNCTION__, nesvnic->nic_cq.cq_number,
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX],
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]);
+ cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+ /* Send CreateQP request to CQP */
+ nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
+ nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
+ cpu_to_le32((u32)NES_NIC_CTX_SIZE |
+ ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
+ dprintk("%s: RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
+ __FUNCTION__,
+ nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
+ nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
+ if (0!= nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE)) {
+ dprintk("%s: Enabling NIC Backing Store.\n", __FUNCTION__);
+ nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
+ }
+ dprintk("NES_NIC_CTX_SIZE = %0x, word0 = %u.\n",
+ NES_NIC_CTX_SIZE, nic_context->context_words[NES_NIC_CTX_MISC_IDX]);
+
+ u64temp = (u64)nesvnic->nic.sq_pbase;
+ nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+ u64temp = (u64)nesvnic->nic.rq_pbase;
+ nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
+ NES_CQP_QP_TYPE_NIC);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+ u64temp = (u64)nesvnic->nic_cq.cq_pbase +
+ (nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+ nesdev->cqp.sq_head = cqp_head;
+
+ barrier();
+ dprintk("%s:%u Before cqp wqe alloc, sq_head=%u, sq_tail=%u, cqp_head=%u\n",
+ __FUNCTION__, __LINE__, nesdev->cqp.sq_head, nesdev->cqp.sq_tail, cqp_head);
+
+ /* Ring doorbell (2 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("Waiting for create NIC QP%u to complete.\n", nesvnic->nic.qp_id);
+ /* cqp_head = (cqp_head+1) & (nesdev->cqp.sq_size-1); */
+
+ dprintk("%s:%u Before wait_event_timeout, sq_head=%u, sq_tail=%u, cqp_head=%u\n",
+ __FUNCTION__, __LINE__, nesdev->cqp.sq_head, nesdev->cqp.sq_tail, cqp_head);
+
+ ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+ NES_EVENT_TIMEOUT);
+ dprintk("Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
+ nesvnic->nic.qp_id, ret);
+ if (!ret) {
+ dprintk("NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
+ pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+ nesvnic->nic_pbase);
+ return(-EIO);
+ }
+
+ /* Populate the RQ */
+ for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
+ skb = dev_alloc_skb(nesvnic->max_frame_size);
+ if (!skb) {
+ dprintk(KERN_ERR PFX "%s: out of memory for receive skb\n", netdev->name);
+
+ nes_destroy_nic_qp(nesvnic);
+ return(-ENOMEM);
+ }
+
+ skb->dev = netdev;
+
+ pmem = pci_map_single(nesdev->pcidev, skb->data,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+ nic_rqe = &nesvnic->nic.rq_vbase[counter];
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
+ nesvnic->nic.rx_skb[counter] = skb;
+ }
+
+ wqe_count = NES_NIC_WQ_SIZE - 1;
+ nesvnic->nic.rq_head = wqe_count - 1;
+ barrier();
+ do {
+ counter = min(wqe_count, ((u32)255));
+ wqe_count -= counter;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
+ } while (wqe_count);
+#ifdef NES_INT_MODERATE
+ dprintk("%s: Default Interrupt Moderation Enabled\n", __FUNCTION__);
+#endif
+#ifdef NES_NAPI
+ dprintk("%s: NAPI support Enabled\n", __FUNCTION__);
+#endif
+
+ return (0);
+}
+
+
+/**
+ * nes_destroy_nic_qp
+ */
+void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
+{
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ u64 wqe_frag;
+ u32 cqp_head;
+ unsigned long flags;
+ int ret;
+
+ dprintk("%s:%u\n", __FUNCTION__, __LINE__);
+
+ /* Free remaining NIC receive buffers */
+ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
+ nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+ wqe_frag = nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX];
+ wqe_frag += ((u64)nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]) << 32;
+ pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
+ nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
+ }
+
+ /* Destroy NIC QP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_head = nesdev->cqp.sq_head;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic_cq.cq_number);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+ cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+ /* Destroy NIC CQ */
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ |
+ ((u32)nesvnic->nic_cq.cq_size << 16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic_cq.cq_number |
+ ((u32)nesdev->nic_ceq_index << 16));
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ if (++cqp_head >= nesdev->cqp.sq_size)
+ cqp_head = 0;
+
+ nesdev->cqp.sq_head = cqp_head;
+ barrier();
+
+ /* Ring doorbell (2 WQEs) */
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ dprintk("Waiting for destroy NIC QP to complete.\n");
+ /* cqp_head = (cqp_head + 1) & (nesdev->cqp.sq_size - 1); */
+
+ dprintk("%s[%u] Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
+ " cqp.sq_tail=%u, cqp.sq_size=%u\n",
+ __FUNCTION__, __LINE__, cqp_head, nesdev->cqp.sq_head,
+ nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
+
+ ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
+ NES_EVENT_TIMEOUT);
+
+ dprintk("Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
+ " cqp.sq_head=%u, cqp.sq_tail=%u\n",
+ ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+ if (!ret) {
+ dprintk("NIC QP%u destroy timeout expired\n", nesvnic->nic.qp_id);
+ }
+
+ pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
+ nesvnic->nic_pbase);
+}
+
+
+#ifdef NES_NAPI
+/**
+ * nes_napi_isr
+ */
+int nes_napi_isr(struct nes_device *nesdev)
+{
+ u32 int_stat;
+
+#ifdef NES_LEGACY_INT_DETECT
+ /* interrupt status has already been read in ISR */
+ int_stat = nesdev->int_stat;
+#else
+ int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+ /* save off the interrupt status so we avoid the extra read */
+ nesdev->int_stat = int_stat;
+ nesdev->napi_isr_ran = 1;
+ /* int_stat &= (nesdev->int_req | NES_INT_TIMER); */
+#endif
+
+ int_stat &= nesdev->int_req;
+ /* dprintk("%s: Interrupt Status (postfilter) = 0x%08X\n", __FUNCTION__, int_stat ); */
+ /* iff NIC, process here, else wait for DPC */
+ if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
+ nes_write32(nesdev->regs+NES_INT_STAT,
+ (int_stat &
+ ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+
+ /* Process the CEQs */
+ nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
+
+ if (nesdev->et_rx_coalesce_usecs_irq) {
+ if ((nesdev->int_req & NES_INT_TIMER) == 0) {
+ /* Enable Periodic timer interrupts */
+ nesdev->int_req |= NES_INT_TIMER;
+ /* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
+ /* TODO: need to also ack other unused periodic timer values, get from nesadapter */
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+ ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+ }
+ /* Enable interrupts, except CEQs */
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+ } else {
+ /* Enable interrupts, make sure timer is off */
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ }
+
+ return (1);
+ } else {
+ return (0);
+ }
+}
+#endif
+
+
+/**
+ * nes_dpc
+ */
+void nes_dpc(unsigned long param)
+{
+ struct nes_device *nesdev = (struct nes_device *)param;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ u32 counter;
+ u32 loop_counter = 0;
+ u32 int_status_bit;
+ u32 int_stat;
+ u32 timer_stat;
+ u32 temp_int_stat;
+ u32 intf_int_stat;
+ u32 debug_error;
+ u32 processed_intf_int = 0;
+ u32 u32Temp;
+ u16 processed_timer_int = 0;
+ u16 completion_ints = 0;
+ u16 timer_ints = 0;
+
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+
+ do {
+ timer_stat = 0;
+ if (nesdev->napi_isr_ran) {
+ nesdev->napi_isr_ran = 0;
+ int_stat = nesdev->int_stat;
+ } else
+ int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
+ if (0 != processed_intf_int) {
+ int_stat &= nesdev->int_req & ~NES_INT_INTF;
+ } else {
+ int_stat &= nesdev->int_req;
+ }
+ if (0 == processed_timer_int) {
+ processed_timer_int = 1;
+ if (int_stat & NES_INT_TIMER) {
+ timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
+ if ((timer_stat & nesdev->timer_int_req) == 0) {
+ int_stat &= ~NES_INT_TIMER;
+ }
+ }
+ } else {
+ int_stat &= ~NES_INT_TIMER;
+ }
+
+ if (int_stat) {
+ if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+ /* Ack the interrupts */
+ nes_write32(nesdev->regs+NES_INT_STAT,
+ (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ }
+
+ temp_int_stat = int_stat;
+ for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
+ if (int_stat & int_status_bit) {
+ nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
+ temp_int_stat &= ~int_status_bit;
+ completion_ints = 1;
+ }
+ if (!(temp_int_stat & 0x0000ffff))
+ break;
+ int_status_bit <<= 1;
+ }
+
+ /* Process the AEQ for this pci function */
+ int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
+ if (int_stat & int_status_bit) {
+ nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
+ }
+
+ /* Process the MAC interrupt for this pci function */
+ int_status_bit = 1 << (24 + nesdev->mac_index);
+ if (int_stat & int_status_bit) {
+ nes_process_mac_intr(nesdev, nesdev->mac_index);
+ }
+
+ if (int_stat & NES_INT_TIMER) {
+ if (timer_stat & nesdev->timer_int_req) {
+ nes_write32(nesdev->regs + NES_TIMER_STAT,
+ (timer_stat & nesdev->timer_int_req) |
+ ~(nesdev->nesadapter->timer_int_req));
+ timer_ints = 1;
+ }
+ }
+
+ if (int_stat & NES_INT_INTF) {
+ processed_intf_int = 1;
+ intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
+ printk(KERN_ERR PFX "Interface Interrupt Status (prefilter)=0x%08X\n",
+ intf_int_stat);
+ intf_int_stat &= nesdev->intf_int_req;
+ if (NES_INTF_INT_CRITERR & intf_int_stat) {
+ debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
+ printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
+ (u16)debug_error);
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
+ 0x01010000 | (debug_error & 0x0000ffff));
+ /* BUG(); */
+ if (crit_err_count++ > 10)
+ nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
+ }
+ if (NES_INTF_INT_PCIERR & intf_int_stat) {
+ printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
+ BUG();
+ }
+ if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
+ printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
+ BUG();
+ }
+ nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
+ }
+
+ if (int_stat & NES_INT_TSW) {
+ }
+ }
+ /* Don't use the interface interrupt bit stay in loop */
+ int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+ } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
+
+ if (1 == timer_ints) {
+ if (nesdev->et_rx_coalesce_usecs_irq) {
+ if (0 == completion_ints) {
+ nesdev->timer_only_int_count++;
+ if (nesdev->timer_only_int_count>=NES_TIMER_INT_LIMIT) {
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ } else {
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ }
+ } else {
+ nesdev->timer_only_int_count = 0;
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ }
+ } else {
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req &= ~NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ }
+ } else {
+ if ((1 == completion_ints) && (nesdev->et_rx_coalesce_usecs_irq)) {
+ /* dprintk("Enabling periodic timer interrupt.\n" ); */
+ nesdev->timer_only_int_count = 0;
+ nesdev->int_req |= NES_INT_TIMER;
+ nes_write32(nesdev->regs+NES_TIMER_STAT,
+ nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
+ nes_write32(nesdev->regs+NES_INTF_INT_MASK,
+ ~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
+ } else {
+ nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ }
+ }
+}
+
+
+/**
+ * nes_process_ceq
+ */
+void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
+{
+ u64 u64temp;
+ struct nes_hw_cq *cq;
+ u32 head;
+ u32 ceq_size;
+
+ /* dprintk("%s:%u\n", __FUNCTION__, __LINE__); */
+ head = ceq->ceq_head;
+ ceq_size = ceq->ceq_size;
+
+ do {
+ if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
+ NES_CEQE_VALID) {
+ u64temp = *((u64 *)&ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX]);
+ u64temp <<= 1;
+ cq = *((struct nes_hw_cq **)&u64temp);
+ /* dprintk(KERN_ERR PFX "%s: pCQ = %p\n", __FUNCTION__, cq ); */
+ barrier();
+ ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
+
+ /* call the event handler */
+ cq->ce_handler(nesdev, cq);
+
+ if (++head >= ceq_size)
+ head = 0;
+ } else {
+ break;
+ }
+ } while (1);
+
+ ceq->ceq_head = head;
+ /* dprintk("%s:%u\n", __FUNCTION__, __LINE__); */
+}
+
+
+/**
+ * nes_process_aeq
+ */
+void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
+{
+ u64 u64temp;
+ u32 head;
+ u32 aeq_size;
+ struct nes_hw_aeqe volatile *aeqe;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ head = aeq->aeq_head;
+ aeq_size = aeq->aeq_size;
+
+ do {
+ aeqe = &aeq->aeq_vbase[head];
+ if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
+ break;
+ aeqe->aeqe_words[NES_AEQE_MISC_IDX] =
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX] =
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+ if (aeqe->aeqe_words[NES_AEQE_MISC_IDX] & (NES_AEQE_QP|NES_AEQE_CQ)) {
+ if (aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX] >= NES_FIRST_QPN) {
+ /* dealing with an accelerated QP related AE */
+ u64temp = *((u64 *)&aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+ nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
+ } else {
+ /* TODO: dealing with a CQP related AE */
+ dprintk("%s: Processing CQP related AE, misc = 0x%04X\n", __FUNCTION__,
+ (u16)(aeqe->aeqe_words[NES_AEQE_MISC_IDX] >> 16));
+ }
+ } else if (aeqe->aeqe_words[NES_AEQE_MISC_IDX] & NES_AEQE_CQ) {
+ /* dealing with a CQ related AE */
+ dprintk("%s: Processing CQ realated AE, misc = 0x%04X\n", __FUNCTION__,
+ (u16)(aeqe->aeqe_words[NES_AEQE_MISC_IDX] >> 16));
+ }
+
+ aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
+
+ if (++head >= aeq_size)
+ head = 0;
+ }
+ while (1);
+ aeq->aeq_head = head;
+}
+
+
+/**
+ * nes_process_mac_intr
+ */
+void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
+{
+ unsigned long flags;
+ u32 pcs_control_status;
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct nes_vnic *nesvnic;
+ u32 mac_status;
+ u32 mac_index = nesdev->mac_index;
+ u32 u32temp;
+ u16 phy_data;
+ u16 temp_phy_data;
+
+ spin_lock_irqsave(&nesadapter->phy_lock, flags);
+ if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+ return;
+ }
+ nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
+ spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
+
+ /* ack the MAC interrupt */
+ mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
+ /* Clear the interrupt */
+ nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
+
+ dprintk("MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
+
+ if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
+ nesdev->link_status_interrupts++;
+ /* read the PHY interrupt status register */
+ if (nesadapter->OneG_Mode) {
+ do {
+ nes_read_1G_phy_reg(nesdev, 0x1a,
+ nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy%d data from register 0x1a = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+ } while (phy_data&0x8000);
+
+ temp_phy_data = 0;
+ do {
+ nes_read_1G_phy_reg(nesdev, 0x11,
+ nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy%d data from register 0x11 = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+ if (temp_phy_data == phy_data)
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+
+ nes_read_1G_phy_reg(nesdev, 0x1e,
+ nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("Phy%d data from register 0x1e = 0x%X.\n",
+ nesadapter->phy_index[mac_index], phy_data);
+
+ nes_read_1G_phy_reg(nesdev, 1,
+ nesadapter->phy_index[mac_index], &phy_data);
+ dprintk("1G phy%u data from register 1 = 0x%X\n",
+ nesadapter->phy_index[mac_index], phy_data);
+
+ if (temp_phy_data & 0x1000) {
+ dprintk("The Link is up according to the PHY\n");
+ phy_data = 4;
+ } else {
+ dprintk("The Link is down according to the PHY\n");
+ }
+ }
+ dprintk("%s: Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n", __FUNCTION__,
+ nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
+ nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+ dprintk("%s: PCS PHY Control/Status%u: 0x%08X\n", __FUNCTION__,
+ mac_index, pcs_control_status);
+ if (nesadapter->OneG_Mode) {
+ u32temp = 0x01010000;
+ if (nesadapter->port_count > 2) {
+ u32temp |= 0x02020000;
+ }
+ if ((pcs_control_status & u32temp)!= u32temp) {
+ phy_data = 0;
+ dprintk("PCS says the link is down\n");
+ }
+ } else {
+ phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+ }
+
+ if (phy_data & 0x0004) {
+ nesadapter->mac_link_down[mac_index] = 0;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ dprintk("The Link is UP!!. linkup was %d\n", nesvnic->linkup);
+ if (nesvnic->linkup == 0) {
+ printk(PFX "The Link is now up for port %u, netdev %p.\n",
+ mac_index, nesvnic->netdev);
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_start_queue(nesvnic->netdev);
+ nesvnic->linkup = 1;
+ netif_carrier_on(nesvnic->netdev);
+ }
+ }
+ } else {
+ nesadapter->mac_link_down[mac_index] = 1;
+ list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
+ dprintk("The Link is Down!!. linkup was %d\n", nesvnic->linkup);
+ if (nesvnic->linkup == 1) {
+ printk(PFX "The Link is now down for port %u, netdev %p.\n",
+ mac_index, nesvnic->netdev);
+ if (!(netif_queue_stopped(nesvnic->netdev)))
+ netif_stop_queue(nesvnic->netdev);
+ nesvnic->linkup = 0;
+ netif_carrier_off(nesvnic->netdev);
+ }
+ }
+ }
+ }
+
+ nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
+}
+
+
+#ifdef NES_NAPI
+/**
+ * nes_nic_napi_ce_handler
+ */
+void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+ struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+
+ netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index]);
+}
+#endif
+
+
+/**
+ * nes_nic_ce_handler
+ */
+void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
+{
+ dma_addr_t bus_address;
+ struct nes_hw_nic *nesnic;
+ struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
+ struct nes_hw_nic_rq_wqe *nic_rqe;
+ struct nes_hw_nic_sq_wqe *nic_sqe;
+ struct sk_buff *skb;
+ struct sk_buff *rx_skb;
+ u16 *wqe_fragment_length;
+ u64 *wqe_fragment_address;
+ unsigned long flags;
+ u32 head;
+ u32 cq_size;
+ u32 rx_pkt_size;
+ u32 cqe_count=0;
+ u32 cqe_errv;
+ u32 cqe_misc;
+ u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
+ u16 vlan_tag;
+ u16 pkt_type;
+
+ /* dprintk("%s:%u:\n", __FUNCTION__, __LINE__); */
+
+ head = cq->cq_head;
+ cq_size = cq->cq_size;
+#ifdef NES_NAPI
+ nesvnic->cqes_pending = 1;
+#endif
+ do {
+ if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
+ NES_NIC_CQE_VALID) {
+ nesnic = &nesvnic->nic;
+ cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
+ if (cqe_misc & NES_NIC_CQE_SQ) {
+
+ wqe_fragment_index = 1;
+ /* dprintk("%s: Processing SQ completion for QP%u. SQ Tail = %u.\n", __FUNCTION__,
+ nesvnic->nic.qp_id, nesnic->sq_tail); */
+ nic_sqe = &nesnic->sq_vbase[nesnic->sq_tail];
+ skb = nesnic->tx_skb[nesnic->sq_tail];
+ wqe_fragment_length = (u16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
+ /* bump past the vlan tag */
+ wqe_fragment_length++;
+ if (wqe_fragment_length[wqe_fragment_index] != 0) {
+ wqe_fragment_address = (u64 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX];
+ bus_address = (dma_addr_t)le64_to_cpu(wqe_fragment_address[wqe_fragment_index]);
+ if ((skb) && (skb_headlen(skb) > NES_FIRST_FRAG_SIZE)) {
+ pci_unmap_single(nesdev->pcidev,
+ bus_address,
+ le32_to_cpu(wqe_fragment_length[wqe_fragment_index++]),
+ PCI_DMA_TODEVICE);
+ }
+ for (; wqe_fragment_index < 5; wqe_fragment_index++) {
+ if (wqe_fragment_length[wqe_fragment_index]) {
+ bus_address = (dma_addr_t)le64_to_cpu(wqe_fragment_address[wqe_fragment_index]);
+ pci_unmap_page(nesdev->pcidev,
+ bus_address,
+ le32_to_cpu(wqe_fragment_length[wqe_fragment_index]),
+ PCI_DMA_TODEVICE);
+ } else
+ break;
+ }
+ if (skb)
+ dev_kfree_skb_any(skb);
+ }
+ spin_lock_irqsave(&nesnic->sq_lock, flags);
+ nesnic->sq_tail++;
+ nesnic->sq_tail &= nesnic->sq_size-1;
+ /* restart the queue if it had been stopped */
+ if (netif_queue_stopped(nesvnic->netdev))
+ netif_wake_queue(nesvnic->netdev);
+ spin_unlock_irqrestore(&nesnic->sq_lock, flags);
+ } else {
+
+#ifdef NES_NAPI
+ nesvnic->rx_cqes_completed++;
+#endif
+ rx_pkt_size = cqe_misc & 0x0000ffff;
+ /* dprintk("%s: Processing RQ completion for QP%u. RQ Tail = %u, size = %u.\n",
+ __FUNCTION__, nesvnic->nic.qp_id, nesnic->rq_tail, rx_pkt_size); */
+ nic_rqe = &nesnic->rq_vbase[nesnic->rq_tail];
+ /* Get the skb */
+ rx_skb = nesnic->rx_skb[nesnic->rq_tail];
+ nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_tail];
+ bus_address = le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
+ pci_unmap_single(nesdev->pcidev, bus_address,
+ nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+ rx_skb->tail = rx_skb->data + rx_pkt_size;
+ rx_skb->len = rx_pkt_size;
+ rx_skb->protocol = eth_type_trans(rx_skb, nesvnic->netdev);
+ nesnic->rq_tail++;
+ nesnic->rq_tail &= nesnic->rq_size - 1;
+
+ skb = dev_alloc_skb(nesvnic->max_frame_size);
+ if (skb) {
+ /* dprintk("skb %p added to the RQ at index %u.\n", skb, nesnic->rq_head); */
+ skb->dev = nesvnic->netdev;
+
+ bus_address = pci_map_single(nesdev->pcidev,
+ skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
+
+ nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
+ cpu_to_le32(nesvnic->max_frame_size);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32((u32)bus_address);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)((u64)bus_address >> 32));
+ nesnic->rx_skb[nesnic->rq_head] = skb;
+ nesnic->rq_head++;
+ nesnic->rq_head &= nesnic->rq_size - 1;
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, (1 << 24) | nesnic->qp_id);
+ } else {
+ dprintk("%s[%u] alloc_skb failed!\n", __FUNCTION__, __LINE__);
+ }
+
+ pkt_type = (u16)(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]));
+ cqe_errv = (cqe_misc & NES_NIC_CQE_ERRV_MASK) >> NES_NIC_CQE_ERRV_SHIFT;
+ rx_skb->ip_summed = CHECKSUM_NONE;
+
+ if ((NES_PKT_TYPE_TCPV4_BITS == (pkt_type & NES_PKT_TYPE_TCPV4_MASK)) ||
+ (NES_PKT_TYPE_UDPV4_BITS == (pkt_type & NES_PKT_TYPE_UDPV4_MASK))) {
+ if (0 == (cqe_errv &
+ (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR |
+ NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
+ NES_NIC_ERRV_BITS_IPH_ERR |
+ NES_NIC_ERRV_BITS_WQE_OVERRUN))) {
+ if (0 == nesvnic->rx_checksum_disabled) {
+ rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ /* dprintk("%s: Reporting successfully checksummed TCP or UDP packet.\n",
+ nesvnic->netdev->name); */
+ }
+ } else {
+ dprintk("%s: unsuccessfully checksummed TCP or UDP packet."
+ " errv = 0x%X, pkt_type = 0x%X.\n",
+ nesvnic->netdev->name, cqe_errv, pkt_type);
+ }
+ } else if (NES_PKT_TYPE_IPV4_BITS == (pkt_type & NES_PKT_TYPE_IPV4_MASK)) {
+ if (0 == (cqe_errv &
+ (NES_NIC_ERRV_BITS_IPV4_CSUM_ERR |
+ NES_NIC_ERRV_BITS_IPH_ERR |
+ NES_NIC_ERRV_BITS_WQE_OVERRUN))) {
+ if (0 == nesvnic->rx_checksum_disabled) {
+ rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
+ /* dprintk("%s: Reporting successfully checksummed IPv4 packet.\n",
+ nesvnic->netdev->name); */
+ }
+ } else {
+ dprintk("%s: unsuccessfully checksummed TCP or UDP packet."
+ " errv = 0x%X, pkt_type = 0x%X.\n",
+ nesvnic->netdev->name, cqe_errv, pkt_type);
+ }
+ }
+ /* dprintk("%s:%u: pkt_type=%x, APBVT_MASK=%x\n", __FUNCTION__, __LINE__,
+ pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
+
+ if (NES_PKT_TYPE_APBVT_BITS == (pkt_type & NES_PKT_TYPE_APBVT_MASK)) {
+ /* dprintk("%s:%u: APBVT bit set; Send up NES; nesif_rx\n",
+ __FUNCTION__, __LINE__); */
+ nes_cm_recv(rx_skb, nesvnic->netdev);
+ } else {
+ if (cqe_misc & NES_NIC_CQE_TAG_VALID) {
+ vlan_tag = (u16)(le32_to_cpu(
+ cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
+ >> 16);
+ dprintk("%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
+ nesvnic->netdev->name, vlan_tag);
+
+#ifdef NES_NAPI
+ vlan_hwaccel_receive_skb(rx_skb, nesvnic->vlan_grp, vlan_tag);
+#else
+ vlan_hwaccel_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+#endif
+ } else {
+#ifdef NES_NAPI
+ netif_receive_skb(rx_skb);
+#else
+ netif_rx(rx_skb);
+#endif
+ }
+ }
+
+ nesvnic->netdev->last_rx = jiffies;
+ /* nesvnic->netstats.rx_packets++; */
+ /* nesvnic->netstats.rx_bytes += rx_pkt_size; */
+ }
+
+ cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
+ /* Accounting... */
+ cqe_count++;
+ if (++head >= cq_size)
+ head = 0;
+ if (cqe_count == 255) {
+ /* Arm the CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC,
+ cq->cq_number | (cqe_count << 16));
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+ cqe_count = 0;
+ }
+#ifdef NES_NAPI
+ if (nesvnic->rx_cqes_completed >= nesvnic->budget)
+ break;
+#endif
+ } else {
+ nesvnic->cqes_pending = 0;
+ break;
+ }
+ } while (1);
+
+ cq->cq_head = head;
+ /* dprintk("CQ%u Processed = %u cqes, new head = %u.\n",
+ cq->cq_number, cqe_count, cq->cq_head); */
+#ifdef NES_NAPI
+ nesvnic->cqe_allocs_pending = cqe_count;
+#else
+ /* Arm the CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ cq->cq_number | (cqe_count << 16));
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+#endif
+}
+
+/**
+ * nes_cqp_ce_handler
+ */
+void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
+{
+ struct nes_hw_cqp *cqp = NULL;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ u32 head;
+ u32 cq_size;
+ u32 cqe_count=0;
+ unsigned long flags;
+ /* u32 counter; */
+
+ /* dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); */
+ head = cq->cq_head;
+ cq_size = cq->cq_size;
+ /* dprintk("%s:%u head=%u, cq_size=%u\n",
+ __FUNCTION__, __LINE__, head, cq_size); */
+
+ do {
+ /* process the CQE */
+ /* dprintk("%s:%u head=%u cqe_words=%08X\n", __FUNCTION__, __LINE__, head,
+ cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]); */
+
+ if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
+ cqp = *((struct nes_hw_cqp **)&cq->cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+
+ /* dprintk("%s:%u cqp=%p, cqp->sq_head=%u, cqp->sq_tail=%u\n", __FUNCTION__, __LINE__,
+ cqp, cqp->sq_head, cqp->sq_tail); */
+ if (cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]) {
+ cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] =
+ le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+ dprintk("%s[%u] Bad Completion code for opcode 0x%02X from CQP,"
+ " Major/Minor codes = 0x%04X:%04X.\n",
+ __FUNCTION__, __LINE__,
+ le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,
+ (u16)(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] >> 16),
+ (u16)cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+ dprintk("%s[%u] cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n",
+ __FUNCTION__, __LINE__,
+ cqp->qp_id, cqp->sq_head, cqp->sq_tail);
+ }
+
+ cqp_request = *((struct nes_cqp_request **)
+ &nesdev->cqp.sq_vbase[cqp->sq_tail].wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]);
+ if (++cqp->sq_tail >= cqp->sq_size)
+ cqp->sq_tail = 0;
+
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
+
+ if (cqp_request) {
+ if (cqp_request->waiting) {
+ /* dprintk("%s: Waking up requestor\n", __FUNCTION__); */
+ cqp_request->major_code =
+ le16_to_cpu((u16)(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] >> 16));
+ cqp_request->minor_code =
+ le16_to_cpu((u16)cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+ barrier();
+ cqp_request->request_done = 1;
+ wake_up(&cqp_request->waitq);
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ dprintk("%s: CQP request %p (opcode 0x%02X) freed.\n", __FUNCTION__,
+ cqp_request, cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]&0x3f);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ } else {
+ /* printk("%s: cqp requestor not waiting\n", __FUNCTION__); */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ dprintk("%s: CQP request %p (opcode 0x%02X) freed.\n", __FUNCTION__,
+ cqp_request, cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]&0x3f);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ } else {
+ wake_up(&nesdev->cqp.waitq);
+ }
+
+ cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
+ /* Accounting... */
+ cqe_count++;
+ if (++head >= cq_size)
+ head = 0;
+ } else {
+ break;
+ }
+ } while (1);
+ cq->cq_head = head;
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ while ((!list_empty(&nesdev->cqp_pending_reqs)) &&
+ ((((nesdev->cqp.sq_tail+nesdev->cqp.sq_size)-nesdev->cqp.sq_head) &
+ (nesdev->cqp.sq_size - 1)) != 1) ) {
+ cqp_request = list_entry(nesdev->cqp_pending_reqs.next,
+ struct nes_cqp_request, list);
+ list_del_init(&cqp_request->list);
+ head = nesdev->cqp.sq_head++;
+ nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
+ cqp_wqe = &nesdev->cqp.sq_vbase[head];
+ memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
+ barrier();
+ *((struct nes_cqp_request **)&cqp_wqe->wqe_words
+ [NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]) = cqp_request;
+ dprintk("%s: CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n", __FUNCTION__,
+ cqp_request, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]&0x3f, head);
+ /* Ring doorbell (1 WQEs) */
+ barrier();
+ nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
+ }
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ /* Arm the CCQ */
+ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
+ cq->cq_number);
+ nes_read32(nesdev->regs+NES_CQE_ALLOC);
+}
+
+
+/**
+ * nes_process_iwarp_aeqe
+ */
+void nes_process_iwarp_aeqe(struct nes_device *nesdev, struct nes_hw_aeqe *aeqe)
+{
+ u64 context;
+ struct nes_qp *nesqp;
+ /* struct iw_cm_id *cm_id; */
+ struct nes_adapter *nesadapter = nesdev->nesadapter;
+ struct ib_event ibevent;
+ /* struct iw_cm_event cm_event; */
+ u32 aeq_info;
+ u32 next_iwarp_state = 0;
+ u16 async_event_id;
+ u8 tcp_state;
+ u8 iwarp_state;
+ unsigned long flags;
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ context = aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX];
+ context += ((u64)aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]) << 32;
+ aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+ async_event_id = (u16)aeq_info;
+ tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
+ iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
+ dprintk("%s: aeid = 0x%04X, qp-cq id = %d, aeqe = %p, Tcp state = %s, iWARP state = %s\n",
+ __FUNCTION__, async_event_id,
+ le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
+ nes_tcp_state_str[tcp_state],
+ nes_iwarp_state_str[iwarp_state]);
+
+ switch (async_event_id) {
+ case NES_AEQE_AEID_LLP_FIN_RECEIVED:
+ nesqp = *((struct nes_qp **)&context);
+ if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ (nesqp->ibqp_state != IB_QPS_RTS)) {
+ /* FIN Received but tcp state or IB state moved on,
+ should expect a close complete */
+ return;
+ }
+ /* TODO: start timer to make sure close complete occurs */
+ case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
+ case NES_AEQE_AEID_LLP_CONNECTION_RESET:
+ case NES_AEQE_AEID_TERMINATE_SENT:
+ case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
+ case NES_AEQE_AEID_RESET_SENT:
+ nesqp = *((struct nes_qp **)&context);
+ if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
+ tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ }
+ nes_add_ref(&nesqp->ibqp);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+
+ if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
+ (tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
+ nesqp->hte_added = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk(PFX "%s: issuing hw modifyqp for QP%u to remove hte\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ nes_hw_modify_qp(nesdev, nesqp,
+ NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ }
+
+ if ((nesqp->ibqp_state == IB_QPS_RTS) &&
+ ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ (async_event_id==NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ switch (nesqp->hw_iwarp_state) {
+ case NES_AEQE_IWARP_STATE_RTS:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
+ break;
+ case NES_AEQE_IWARP_STATE_TERMINATE:
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
+ nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
+ if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+ next_iwarp_state |= 0x02000000;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ }
+ break;
+ default:
+ next_iwarp_state = 0;
+ }
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ if (next_iwarp_state) {
+ nes_add_ref(&nesqp->ibqp);
+ dprintk(PFX "%s: issuing hw modifyqp for QP%u. next state = 0x%08X,"
+ " also added another reference\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, next_iwarp_state);
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+ }
+ nes_cm_disconn(nesqp);
+ } else {
+ if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) {
+ /* FIN Received but ib state not RTS,
+ close complete will be on its way */
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ return;
+ }
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ if (async_event_id==NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
+ next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000;
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ dprintk(PFX "%s: issuing hw modifyqp for QP%u. next state = 0x%08X,"
+ " also added another reference\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, next_iwarp_state);
+ nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
+ }
+ nes_cm_disconn(nesqp);
+ }
+ break;
+ case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED"
+ " event on QP%u \n Q2 Data:\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ ((nesqp->ibqp_state == IB_QPS_RTS)&&
+ (async_event_id==NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ } else {
+ nesqp->in_disconnect = 0;
+ wake_up(&nesqp->kick_waitq);
+ }
+ break;
+ case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
+ if (NES_AEQE_INBOUND_RDMA&aeq_info) {
+ nesqp = nesadapter->qp_table[le32_to_cpu(
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ } else {
+ /* TODO: get the actual WQE and mask off wqe index */
+ context &= ~((u64)511);
+ nesqp = *((struct nes_qp **)&context);
+ }
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
+ nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words
+ [NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u,"
+ " nesqp = %p, AE reported %p\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context));
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ break;
+ case NES_AEQE_AEID_CQ_OPERATION_ERROR:
+ context <<= 1;
+ dprintk("%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n",
+ __FUNCTION__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), (void *)context);
+ break;
+ case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+ nesqp = nesadapter->qp_table[le32_to_cpu(
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG"
+ "_FOR_AVAILABLE_BUFFER event on QP%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN"
+ "_NO_BUFFER_AVAILABLE event on QP%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
+ nesqp = *((struct nes_qp **)&context);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ nesqp->hw_iwarp_state = iwarp_state;
+ nesqp->hw_tcp_state = tcp_state;
+ nesqp->last_aeq = async_event_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ dprintk("%s: Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR"
+ " event on QP%u \n Q2 Data:\n",
+ __FUNCTION__, nesqp->hwqp.qp_id);
+ if (nesqp->ibqp.event_handler) {
+ ibevent.device = nesqp->ibqp.device;
+ ibevent.element.qp = &nesqp->ibqp;
+ ibevent.event = IB_EVENT_QP_FATAL;
+ nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
+ }
+ /* tell cm to disconnect, cm will queue work to thread */
+ nes_add_ref(&nesqp->ibqp);
+ nes_cm_disconn(nesqp);
+ break;
+ /* TODO: additional AEs need to be here */
+ default:
+ dprintk("%s: Processing an iWARP related AE for QP, misc = 0x%04X\n",
+ __FUNCTION__, async_event_id);
+ break;
+ }
+
+ dprintk("%s:%u: Leaving\n", __FUNCTION__, __LINE__);
+}
+
+
+/**
+ * nes_iwarp_ce_handler
+ */
+void nes_iwarp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *hw_cq)
+{
+ struct nes_cq *nescq = container_of(hw_cq, struct nes_cq, hw_cq);
+
+ /* dprintk("%s: Processing completion event for iWARP CQ%u.\n",
+ __FUNCTION__, nescq->hw_cq.cq_number); */
+ nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number);
+
+ if (nescq->ibcq.comp_handler)
+ nescq->ibcq.comp_handler(&nescq->ibcq, nescq->ibcq.cq_context);
+
+ return;
+}
+
+/**
+ * nes_manage_apbvt()
+ */
+int nes_manage_apbvt(struct nes_vnic *nesvnic, u32 accel_local_port,
+ u32 nic_index, u32 add_port)
+{
+ struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request;
+ int ret;
+ u16 major_code;
+
+ /* Send manage APBVT request to CQP */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return (-ENOMEM);
+ }
+ cqp_request->waiting = 1;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ dprintk("%s:%u: %s APBV for local port=%u(0x%04x), nic_index=%u\n",
+ __FUNCTION__, __LINE__,
+ (add_port == NES_MANAGE_APBVT_ADD) ? "ADD" : "DEL",
+ accel_local_port, accel_local_port, nic_index);
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_MANAGE_APBVT |
+ ((add_port==NES_MANAGE_APBVT_ADD) ? NES_CQP_APBVT_ADD : 0));
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
+ cpu_to_le32((nic_index << NES_CQP_APBVT_NIC_SHIFT) | accel_local_port);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ dprintk("%s: Waiting for CQP completion for APBVT.\n", __FUNCTION__);
+
+ atomic_set(&cqp_request->refcount, 2);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("%s: Completed, ret=%u, CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ __FUNCTION__, ret, cqp_request->major_code, cqp_request->minor_code);
+ major_code = cqp_request->major_code;
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ if (!ret)
+ return(-ETIME);
+ else if (major_code)
+ return(-EIO);
+ else
+ return(0);
+}
+
+
+/**
+ * nes_manage_arp_cache
+ */
+void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
+ u32 ip_addr, u32 action)
+{
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ struct nes_vnic *nesvnic = netdev_priv(netdev);
+ struct nes_device *nesdev;
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request;
+ int arp_index;
+
+ nesdev = nesvnic->nesdev;
+ arp_index = nes_arp_table(nesdev, ip_addr, mac_addr, action);
+ if (arp_index == -1) {
+ /* dprintk("%s:%u nes_arp_table call returned -1\n", __FUNCTION__, __LINE__); */
+ return;
+ }
+
+ /* dprintk("%s: Update the ARP entry, arp_index=%d\n", __FUNCTION__, arp_index); */
+
+ /* update the ARP entry */
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return;
+ }
+ cqp_request->waiting = 0;
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM;
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |=
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT;
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = arp_index;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ if (action == NES_ARP_ADD) {
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= NES_CQP_ARP_VALID;
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] =
+ (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
+ (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5];
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] =
+ (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1];
+ } else {
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
+ }
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX]);
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX]);
+ cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] =
+ cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX]);
+
+ dprintk("%s[%u] Not waiting for CQP, cqp.sq_head=%u, cqp.sq_tail=%u\n",
+ __FUNCTION__, __LINE__, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
+
+ atomic_set(&cqp_request->refcount, 1);
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+}
+
+
+/**
+ * flush_wqes
+ */
+void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp,
+ u32 which_wq, u32 wait_completion)
+{
+ unsigned long flags;
+ struct nes_cqp_request *cqp_request;
+ struct nes_hw_cqp_wqe *cqp_wqe;
+ int ret;
+
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+
+ cqp_request = nes_get_cqp_request(nesdev, NES_CQP_REQUEST_HOLDING_LOCK);
+ if (NULL == cqp_request) {
+ dprintk("%s: Failed to get a cqp_request.\n", __FUNCTION__);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ return;
+ }
+ if (wait_completion) {
+ cqp_request->waiting = 1;
+ atomic_set(&cqp_request->refcount, 2);
+ } else {
+ cqp_request->waiting = 0;
+ }
+ cqp_wqe = &cqp_request->cqp_wqe;
+
+ cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
+ cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq);
+ cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id);
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+ *((struct nes_hw_cqp **)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =
+ &nesdev->cqp;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+ cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+ nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_HOLDING_LOCK,
+ NES_CQP_REQUEST_RING_DOORBELL);
+
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+
+ if (wait_completion) {
+ /* Wait for CQP */
+ ret = wait_event_timeout(cqp_request->waitq, (0 != cqp_request->request_done),
+ NES_EVENT_TIMEOUT);
+ dprintk("Flush SQ QP WQEs completed, ret=%u, CQP Major:Minor codes = 0x%04X:0x%04X\n",
+ ret, cqp_request->major_code, cqp_request->minor_code);
+ if (atomic_dec_and_test(&cqp_request->refcount)) {
+ spin_lock_irqsave(&nesdev->cqp.lock, flags);
+ list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
+ spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+ }
+ }
+}
+
^ permalink raw reply
* [PATCH 5/14] nes: context structures and defines
From: ggrundstrom @ 2007-08-08 1:03 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
QP context structures and defines
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_context.h
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_context.h 2007-08-06 20:09:04.000000000 -0500
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef NES_CONTEXT_H
+#define NES_CONTEXT_H
+
+struct nes_qp_context {
+ u32 misc;
+ u32 cqs;
+ u32 sq_addr_low;
+ u32 sq_addr_high;
+ u32 rq_addr_low;
+ u32 rq_addr_high;
+ u32 misc2;
+ u32 tcpPorts;
+ u32 ip0;
+ u32 ip1;
+ u32 ip2;
+ u32 ip3;
+ u32 mss;
+ u32 arp_index_vlan;
+ u32 tcp_state_flow_label;
+ u32 pd_index_wscale;
+ u32 keepalive;
+ u32 ts_recent;
+ u32 ts_age;
+ u32 snd_nxt;
+ u32 snd_wnd;
+ u32 rcv_nxt;
+ u32 rcv_wnd;
+ u32 snd_max;
+ u32 snd_una;
+ u32 srtt;
+ u32 rttvar;
+ u32 ssthresh;
+ u32 cwnd;
+ u32 snd_wl1;
+ u32 snd_wl2;
+ u32 max_snd_wnd;
+ u32 ts_val_delta;
+ u32 retransmit;
+ u32 probe_cnt;
+ u32 hte_index;
+ u32 q2_addr_low;
+ u32 q2_addr_high;
+ u32 ird_index;
+ u32 Rsvd3;
+ u32 ird_ord_sizes;
+ u32 mrkr_offset;
+ u32 aeq_token_low;
+ u32 aeq_token_high;
+};
+
+/* QP Context Misc Field */
+
+#define NES_QPCONTEXT_MISC_IWARP_VER_MASK 0x00000003
+#define NES_QPCONTEXT_MISC_IWARP_VER_SHIFT 0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_MASK 0x000000C0
+#define NES_QPCONTEXT_MISC_EFB_SIZE_SHIFT 6
+#define NES_QPCONTEXT_MISC_RQ_SIZE_MASK 0x00000300
+#define NES_QPCONTEXT_MISC_RQ_SIZE_SHIFT 8
+#define NES_QPCONTEXT_MISC_SQ_SIZE_MASK 0x00000c00
+#define NES_QPCONTEXT_MISC_SQ_SIZE_SHIFT 10
+#define NES_QPCONTEXT_MISC_PCI_FCN_MASK 0x00007000
+#define NES_QPCONTEXT_MISC_PCI_FCN_SHIFT 12
+#define NES_QPCONTEXT_MISC_DUP_ACKS_MASK 0x00070000
+#define NES_QPCONTEXT_MISC_DUP_ACKS_SHIFT 16
+
+enum nes_qp_context_misc_bits {
+ NES_QPCONTEXT_MISC_RX_WQE_SIZE = 0x00000004,
+ NES_QPCONTEXT_MISC_IPV4 = 0x00000008,
+ NES_QPCONTEXT_MISC_DO_NOT_FRAG = 0x00000010,
+ NES_QPCONTEXT_MISC_INSERT_VLAN = 0x00000020,
+ NES_QPCONTEXT_MISC_DROS = 0x00008000,
+ NES_QPCONTEXT_MISC_WSCALE = 0x00080000,
+ NES_QPCONTEXT_MISC_KEEPALIVE = 0x00100000,
+ NES_QPCONTEXT_MISC_TIMESTAMP = 0x00200000,
+ NES_QPCONTEXT_MISC_SACK = 0x00400000,
+ NES_QPCONTEXT_MISC_RDMA_WRITE_EN = 0x00800000,
+ NES_QPCONTEXT_MISC_RDMA_READ_EN = 0x01000000,
+ NES_QPCONTEXT_MISC_WBIND_EN = 0x10000000,
+ NES_QPCONTEXT_MISC_FAST_REGISTER_EN = 0x20000000,
+ NES_QPCONTEXT_MISC_PRIV_EN = 0x40000000,
+ NES_QPCONTEXT_MISC_NO_NAGLE = 0x80000000
+};
+
+enum nes_qp_acc_wq_sizes {
+ HCONTEXT_TSA_WQ_SIZE_4 = 0,
+ HCONTEXT_TSA_WQ_SIZE_32 = 1,
+ HCONTEXT_TSA_WQ_SIZE_128 = 2,
+ HCONTEXT_TSA_WQ_SIZE_512 = 3
+};
+
+/* QP Context Misc2 Fields */
+#define NES_QPCONTEXT_MISC2_TTL_MASK 0x000000ff
+#define NES_QPCONTEXT_MISC2_TTL_SHIFT 0
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_MASK 0x000000ff
+#define NES_QPCONTEXT_MISC2_HOP_LIMIT_SHIFT 0
+#define NES_QPCONTEXT_MISC2_LIMIT_MASK 0x00000300
+#define NES_QPCONTEXT_MISC2_LIMIT_SHIFT 8
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_MASK 0x0000fc00
+#define NES_QPCONTEXT_MISC2_NIC_INDEX_SHIFT 10
+#define NES_QPCONTEXT_MISC2_SRC_IP_MASK 0x001f0000
+#define NES_QPCONTEXT_MISC2_SRC_IP_SHIFT 16
+#define NES_QPCONTEXT_MISC2_TOS_MASK 0xff000000
+#define NES_QPCONTEXT_MISC2_TOS_SHIFT 24
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_MASK 0xff000000
+#define NES_QPCONTEXT_MISC2_TRAFFIC_CLASS_SHIFT 24
+
+/* QP Context Tcp State/Flow Label Fields */
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_MASK 0x000fffff
+#define NES_QPCONTEXT_TCPFLOW_FLOW_LABEL_SHIFT 0
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_MASK 0xf0000000
+#define NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT 28
+
+enum nes_qp_tcp_state {
+ NES_QPCONTEXT_TCPSTATE_CLOSED = 1,
+ NES_QPCONTEXT_TCPSTATE_EST = 5,
+ NES_QPCONTEXT_TCPSTATE_TIME_WAIT = 11,
+};
+
+/* QP Context PD Index/wscale Fields */
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK 0x0000000f
+#define NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT 0
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK 0x00000f00
+#define NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT 8
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_MASK 0xffff0000
+#define NES_QPCONTEXT_PDWSCALE_PDINDEX_SHIFT 16
+
+/* QP Context Keepalive Fields */
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_MASK 0x0000ffff
+#define NES_QPCONTEXT_KEEPALIVE_DELTA_SHIFT 0
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_MASK 0x00ff0000
+#define NES_QPCONTEXT_KEEPALIVE_PROBE_CNT_SHIFT 16
+#define NES_QPCONTEXT_KEEPALIVE_INTV_MASK 0xff000000
+#define NES_QPCONTEXT_KEEPALIVE_INTV_SHIFT 24
+
+/* QP Context ORD/IRD Fields */
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_MASK 0x0000007f
+#define NES_QPCONTEXT_ORDIRD_ORDSIZE_SHIFT 0
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_MASK 0x00030000
+#define NES_QPCONTEXT_ORDIRD_IRDSIZE_SHIFT 16
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_MASK 0x30000000
+#define NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT 28
+
+enum nes_ord_ird_bits {
+ NES_QPCONTEXT_ORDIRD_WRPDU = 0x02000000,
+ NES_QPCONTEXT_ORDIRD_LSMM_PRESENT = 0x04000000,
+ NES_QPCONTEXT_ORDIRD_ALSMM = 0x08000000,
+ NES_QPCONTEXT_ORDIRD_AAH = 0x40000000,
+ NES_QPCONTEXT_ORDIRD_RNMC = 0x80000000
+};
+
+enum nes_iwarp_qp_state {
+ NES_QPCONTEXT_IWARP_STATE_NONEXIST = 0,
+ NES_QPCONTEXT_IWARP_STATE_IDLE = 1,
+ NES_QPCONTEXT_IWARP_STATE_RTS = 2,
+ NES_QPCONTEXT_IWARP_STATE_CLOSING = 3,
+ NES_QPCONTEXT_IWARP_STATE_TERMINATE = 5,
+ NES_QPCONTEXT_IWARP_STATE_ERROR = 6
+};
+
+
+#endif /* NES_CONTEXT_H */
^ permalink raw reply
* Re: Please pull 'fixes-davem' branch of wireless-2.6
From: David Miller @ 2007-08-08 1:08 UTC (permalink / raw)
To: linville; +Cc: linux-wireless, netdev
In-Reply-To: <20070806201321.GI6442@tuxdriver.com>
From: "John W. Linville" <linville@tuxdriver.com>
Date: Mon, 6 Aug 2007 16:13:21 -0400
> The following changes since commit d4ac2477fad0f2680e84ec12e387ce67682c5c13:
> Linus Torvalds (1):
> Linux 2.6.23-rc2
>
> are available in the git repository at:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6.git fixes-davem
Pulled, thanks John.
^ permalink raw reply
* Re: [RFC] allow device to stop packet mirror behaviour
From: David Miller @ 2007-08-08 1:06 UTC (permalink / raw)
To: johannes; +Cc: netdev, andy, linux-wireless
In-Reply-To: <1186475155.4067.17.camel@johannes.berg>
From: Johannes Berg <johannes@sipsolutions.net>
Date: Tue, 07 Aug 2007 10:25:55 +0200
> The only way to solve this problem therefore seems to be to suppress the
> mirroring out of the packet by dev_queue_xmit_nit(). The patch below
> does that by way of adding a new netdev flag.
Multicast packets also get looped back in a similar manner in the ipv4
code. These will also be seen twice due to this issue.
There are probably many other examples as well, dev_queue_xmit_nit()
is just the tip of the iceberg.
^ permalink raw reply
* Re: [PATCH] net/core/utils: fix sparse warning
From: David Miller @ 2007-08-08 1:03 UTC (permalink / raw)
To: johannes; +Cc: netdev
In-Reply-To: <1186418247.28655.82.camel@johannes.berg>
From: Johannes Berg <johannes@sipsolutions.net>
Date: Mon, 06 Aug 2007 18:37:26 +0200
> net_msg_warn is not defined because it is in net/sock.h which isn't
> included.
>
> Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Applied, thanks Johannes.
^ permalink raw reply
* Re: [PATCH RFC]: napi_struct V5
From: David Miller @ 2007-08-08 0:59 UTC (permalink / raw)
To: hadi; +Cc: netdev, shemminger, jgarzik, rusty
In-Reply-To: <1186491155.5163.68.camel@localhost>
From: jamal <hadi@cyberus.ca>
Date: Tue, 07 Aug 2007 08:52:35 -0400
> That doc is out of date on the split of work - it focusses mostly
> describing the original tulip which did not mix rx and tx in the
> napi_poll(). AFAIK, no driver does that today (although i really liked
> that scheme, there is a lot of fscked hardware out there that wont work
> well with that scheme). Where are the firemen when you need them?
I am tempted to suggest we toss the document completely, for
two reasons:
1) It's geared towards conversions, whereas %99.9999 of the conversions
that will ever happen, have happened. Every single potential reader
of this document is therefore writing new drivers with NAPI from the
beginning.
2) Inaccurate documentation is often worse than no documentation.
It's not a bad thing to delete the document, and also we have a lot
of time until 2.6.24 finalizes with these changes and in that time
someone with the right incentive could write a fresh new NAPI
manual that represents reality. Such a document could be added after
the merge window closes.
This also reminds me that we confuse people by having two driver
models for interrupt handling. I've been reluctant to remove the
"optional" component of NAPI especially when it didn't handle
multi-queue properly (which basically made drivers for virtualized
devices impossible without using dummy devices for each queue).
But that is no longer true and there isn't any reason for a new
driver not to be NAPI from the beginning.
^ permalink raw reply
* [PATCH 4/14] nes: connection manager structures and defines
From: ggrundstrom @ 2007-08-08 0:52 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
NetEffect connection manager includes, structures and defines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_cm.h
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_cm.h 2007-08-07 13:35:50.000000000 -0500
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef NES_CM_H
+#define NES_CM_H
+
+#define QUEUE_EVENTS
+
+#define NES_MANAGE_APBVT_DEL 0
+#define NES_MANAGE_APBVT_ADD 1
+
+/* IETF MPA -- defines, enums, structs */
+#define IEFT_MPA_KEY_REQ "MPA ID Req Frame"
+#define IEFT_MPA_KEY_REP "MPA ID Rep Frame"
+#define IETF_MPA_KEY_SIZE 16
+#define IETF_MPA_VERSION 1
+
+enum ietf_mpa_flags {
+ IETF_MPA_FLAGS_MARKERS = 0x80, /* receive Markers */
+ IETF_MPA_FLAGS_CRC = 0x40, /* receive Markers */
+ IETF_MPA_FLAGS_REJECT = 0x20, /* Reject */
+};
+
+struct ietf_mpa_frame {
+ u8 key[IETF_MPA_KEY_SIZE];
+ u8 flags;
+ u8 rev;
+ u16 priv_data_len;
+ u8 priv_data[0];
+};
+
+#define ietf_mpa_req_resp_frame ietf_mpa_frame
+
+struct nes_v4_quad {
+ u32 rsvd0;
+ u32 DstIpAdrIndex; /* Only most significant 5 bits are valid */
+ u32 SrcIpadr;
+ u32 TcpPorts; /* src is low, dest is high */
+};
+
+struct nes_cm_node;
+enum nes_timer_type
+{
+ NES_TIMER_TYPE_SEND,
+ NES_TIMER_TYPE_RECV,
+ NES_TIMER_NODE_CLEANUP,
+ NES_TIMER_TYPE_CLOSE,
+};
+
+#define MAX_NES_IFS 4
+
+#define SET_ACK 1
+#define SET_SYN 2
+#define SET_FIN 4
+#define SET_RST 8
+
+struct option_base {
+ u8 optionnum;
+ u8 length;
+};
+
+enum option_numbers {
+ OPTION_NUMBER_END,
+ OPTION_NUMBER_NONE,
+ OPTION_NUMBER_MSS,
+ OPTION_NUMBER_WINDOW_SCALE,
+ OPTION_NUMBER_SACK_PERM,
+ OPTION_NUMBER_SACK,
+ OPTION_NUMBER_WRITE0 = 0xbc
+};
+
+struct option_mss {
+ u8 optionnum;
+ u8 length;
+ u16 mss;
+};
+
+struct option_windowscale {
+ u8 optionnum;
+ u8 length;
+ u8 shiftcount;
+};
+
+union all_known_options{
+ char as_end;
+ struct option_base as_base;
+ struct option_mss as_mss;
+ struct option_windowscale as_windowscale;
+};
+
+struct nes_timer_entry
+{
+ struct list_head list;
+ unsigned long timetosend; /* jiffies */
+ struct sk_buff *skb;
+ u32 type;
+ u32 retrycount;
+ u32 retranscount;
+ u32 context;
+ u32 seq_num;
+ u32 send_retrans;
+ struct net_device *netdev;
+};
+
+#define NES_DEFAULT_RETRYS 64
+#define NES_DEFAULT_RETRANS 4
+#define NES_RETRY_TIMEOUT (1000*HZ/1000)
+#define NES_SHORT_TIME (10)
+#define NES_LONG_TIME (2000*HZ/1000)
+
+#define NES_CM_HASHTABLE_SIZE 1024
+#define NES_CM_TCP_TIMER_INTERVAL 3000
+#define NES_CM_DEFAULT_MTU 1540
+#define NES_CM_DEFAULT_FRAME_CNT 10
+#define NES_CM_THREAD_STACK_SIZE 256
+#define NES_CM_DEFAULT_RCV_WND 64240 // before we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALED 256960 // after we know that window scaling is allowed
+#define NES_CM_DEFAULT_RCV_WND_SCALE 2
+#define NES_CM_DEFAULT_FREE_PKTS 0x000A
+#define NES_CM_FREE_PKT_LO_WATERMARK 2
+
+#define NES_CM_DEF_SEQ 0x159bf75f
+#define NES_CM_DEF_LOCAL_ID 0x3b47
+
+#define NES_CM_DEF_SEQ2 0x18ed5740
+#define NES_CM_DEF_LOCAL_ID2 0xb807
+
+typedef u32 nes_addr_t;
+
+#define nes_cm_tsa_context nes_qp_context
+
+struct nes_qp;
+
+/* cm node transition states */
+enum nes_cm_node_state {
+ NES_CM_STATE_UNKNOWN,
+ NES_CM_STATE_INITED,
+ NES_CM_STATE_LISTENING,
+ NES_CM_STATE_SYN_RCVD,
+ NES_CM_STATE_SYN_SENT,
+ NES_CM_STATE_ONE_SIDE_ESTABLISHED,
+ NES_CM_STATE_ESTABLISHED,
+ NES_CM_STATE_ACCEPTING,
+ NES_CM_STATE_MPAREQ_SENT,
+ NES_CM_STATE_TSA,
+ NES_CM_STATE_FIN_WAIT1,
+ NES_CM_STATE_FIN_WAIT2,
+ NES_CM_STATE_CLOSE_WAIT,
+ NES_CM_STATE_TIME_WAIT,
+ NES_CM_STATE_LAST_ACK,
+ NES_CM_STATE_CLOSING,
+ NES_CM_STATE_CLOSED
+};
+
+/* type of nes connection */
+enum nes_cm_conn_type {
+ NES_CM_IWARP_CONN_TYPE,
+};
+
+/* CM context params */
+struct nes_cm_tcp_context {
+ u8 client;
+
+ u32 loc_seq_num;
+ u32 loc_ack_num;
+ u32 rem_ack_num;
+ u32 rcv_nxt;
+
+ u32 loc_id;
+ u32 rem_id;
+
+ u32 snd_wnd;
+ u32 max_snd_wnd;
+
+ u32 rcv_wnd;
+ u32 mss;
+ u8 snd_wscale;
+ u8 rcv_wscale;
+
+ struct nes_cm_tsa_context tsa_cntxt;
+ struct timeval sent_ts;
+};
+
+struct nes_cm_listener {
+ struct list_head list;
+ u64 session_id;
+ struct nes_cm_core *core_p;
+ u8 loc_mac[ETH_ALEN];
+ nes_addr_t loc_addr;
+ u16 loc_port;
+ void *cm_id;
+ enum nes_cm_conn_type conn_type;
+ atomic_t ref_count;
+};
+
+/* per connection node and node state information */
+struct nes_cm_node {
+ u64 session_id;
+ u32 hashkey;
+
+ nes_addr_t loc_addr, rem_addr;
+ u16 loc_port, rem_port;
+
+ u8 loc_mac[ETH_ALEN];
+ u8 rem_mac[ETH_ALEN];
+
+ enum nes_cm_node_state state;
+ struct nes_cm_tcp_context tcp_cntxt;
+ struct nes_cm_core *core_p;
+ struct sk_buff_head resend_list;
+ struct nes_cm_node *listener;
+ atomic_t ref_count;
+ struct net_device *netdev_p;
+
+ struct nes_cm_node *loopbackpartner ;
+ struct list_head retrans_list;
+ spinlock_t retrans_list_lock;
+ struct list_head recv_list;
+ spinlock_t recv_list_lock;
+
+ int send_write0;
+ union {
+ struct ietf_mpa_frame mpa_frame_p;
+ u8 mpa_frame_b[NES_CM_DEFAULT_MTU];
+ };
+ u16 mpa_frame_size;
+ void *cm_id;
+ struct list_head list;
+ int accelerated;
+ struct nes_cm_listener *listen_p;
+ enum nes_cm_conn_type conn_type;
+};
+
+/* structure for client or CM to fill when making CM api calls. */
+/* - only need to set relevant data, based on op. */
+struct nes_cm_info {
+ union {
+ struct iw_cm_id *cm_id;
+ struct net_device *netdev;
+ };
+
+ u16 loc_port;
+ u16 rem_port;
+ nes_addr_t loc_addr;
+ nes_addr_t rem_addr;
+
+ enum nes_cm_conn_type conn_type;
+};
+
+/* CM event codes */
+enum nes_cm_event_type {
+ NES_CM_EVENT_UNKNOWN,
+ NES_CM_EVENT_ESTABLISHED,
+ NES_CM_EVENT_MPA_REQ,
+ NES_CM_EVENT_MPA_CONNECT,
+ NES_CM_EVENT_MPA_ACCEPT,
+ NES_CM_EVENT_MPA_ESTABLISHED,
+ NES_CM_EVENT_CONNECTED,
+ NES_CM_EVENT_CLOSED,
+ NES_CM_EVENT_RESET,
+ NES_CM_EVENT_DROPPED_PKT,
+ NES_CM_EVENT_CLOSE_IMMED,
+ NES_CM_EVENT_CLOSE_HARD,
+ NES_CM_EVENT_CLOSE_CLEAN,
+ NES_CM_EVENT_ABORTED,
+ NES_CM_EVENT_SEND_FIRST
+};
+
+/* event to post to CM event handler */
+struct nes_cm_event {
+ enum nes_cm_event_type type;
+
+ struct nes_cm_info cm_info;
+ struct work_struct event_work;
+ struct nes_cm_node *node_p;
+};
+
+struct nes_cm_core {
+ enum nes_cm_node_state state;
+ atomic_t session_id;
+
+ atomic_t listen_node_cnt;
+ struct nes_cm_node listen_list;
+ spinlock_t listen_list_lock;
+
+ u32 mtu;
+ u32 free_tx_pkt_max;
+ u32 rx_pkt_posted;
+ struct sk_buff_head tx_free_list;
+ atomic_t ht_node_cnt;
+ struct list_head connected_nodes;
+ /* struct list_head hashtable[NES_CM_HASHTABLE_SIZE]; */
+ spinlock_t ht_lock;
+
+ struct timer_list tcp_timer;
+
+ struct nes_cm_ops *api;
+
+ int (*post_event)(struct nes_cm_event *event_p);
+ atomic_t events_posted;
+ struct workqueue_struct *event_wq;
+ struct workqueue_struct *disconn_wq;
+
+ atomic_t node_cnt;
+ u64 aborted_connects;
+ u32 options;
+
+ struct nes_cm_node *current_listen_node;
+};
+
+
+#define NES_CM_SET_PKT_SIZE (1 << 1)
+#define NES_CM_SET_FREE_PKT_Q_SIZE (1 << 2)
+
+/* CM ops/API for client interface */
+struct nes_cm_ops {
+ int (*accelerated)(struct nes_cm_core *cm_core_p,
+ struct nes_cm_node *node_p);
+ struct nes_cm_listener * (*listen)(struct nes_cm_core *cm_core_p,
+ struct nes_vnic *nesvnic, struct nes_cm_info *nfo_p);
+ int (*stop_listener)(struct nes_cm_core *core_p,
+ struct nes_cm_listener *cm_core_p);
+ struct nes_cm_node * (*connect)(struct nes_cm_core *cm_core_p,
+ struct nes_vnic *nesvnic, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_info *nfo_p);
+ int (*close)(struct nes_cm_core *cm_core_p, struct nes_cm_node *node_p);
+ int (*accept)(struct nes_cm_core *cm_core_p, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_node *node_p);
+ int (*reject)(struct nes_cm_core *cm_core_p, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_node *node_p);
+ int (*recv_pkt)(struct nes_cm_core *cm_core_p, struct nes_vnic *nesvnic,
+ struct sk_buff *skb_p);
+ int (*destroy_cm_core)(struct nes_cm_core *core_p);
+ int (*get)(struct nes_cm_core *cm_core_p);
+ int (*set)(struct nes_cm_core *core_p, u32 type, u32 value);
+};
+
+
+int send_mpa_request(struct nes_cm_node *);
+struct sk_buff *form_cm_frame(struct sk_buff *, struct nes_cm_node *,
+ void *, u32, void *, u32, u8);
+int schedule_nes_timer(struct nes_cm_node *node_p, struct sk_buff *skb_p,
+ enum nes_timer_type type, int retransmit);
+void nes_cm_timer_tick(unsigned long);
+int send_syn(struct nes_cm_node *, u32);
+int send_reset(struct nes_cm_node *);
+int send_ack(struct nes_cm_node *);
+int send_fin(struct nes_cm_node *, struct sk_buff *);
+struct sk_buff *get_free_pkt(struct nes_cm_node *);
+int del_hte_node(struct nes_cm_core *, struct nes_cm_node *);
+int process_packet(struct nes_cm_node *node_p, struct sk_buff *skb_p,
+ struct nes_cm_core *core_p);
+
+struct nes_cm_node * mini_cm_connect(struct nes_cm_core *core_p,
+ struct nes_vnic *nesvnic, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_info *nfo_p);
+int mini_cm_accept(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_reject(struct nes_cm_core *, struct ietf_mpa_frame *, struct nes_cm_node *);
+int mini_cm_close(struct nes_cm_core *, struct nes_cm_node *);
+int mini_cm_recv_pkt(struct nes_cm_core *, struct nes_vnic *, struct sk_buff *);
+struct nes_cm_core *mini_cm_alloc_core(struct nes_cm_info *);
+int mini_cm_dealloc_core(struct nes_cm_core *);
+int mini_cm_get(struct nes_cm_core *);
+int mini_cm_set(struct nes_cm_core *, u32, u32);
+
+int nes_cm_disconn(struct nes_qp *nesqp);
+void nes_disconnect_worker(void *);
+int nes_cm_disconn_true(struct nes_qp *);
+int nes_disconnect(struct nes_qp *nesqp, int abrupt, u16 local_port);
+
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len);
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param);
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog);
+int nes_destroy_listen(struct iw_cm_id *cm_id);
+
+int nes_cm_recv(struct sk_buff *, struct net_device *);
+int nes_cm_start(void);
+int nes_cm_stop(void);
+
+/* CM event handler functions */
+void cm_event_connected(struct nes_cm_event *);
+void cm_event_connect_error(struct nes_cm_event *);
+void cm_event_reset(struct nes_cm_event *);
+void cm_event_mpa_req(struct nes_cm_event *);
+int nes_cm_post_event(struct nes_cm_event *);
+
+#endif /* NES_CM_H */
+
^ permalink raw reply
* [PATCH 3/14] nes: connection manager routines
From: ggrundstrom @ 2007-08-08 0:50 UTC (permalink / raw)
To: rdreier; +Cc: ewg, ggrundstrom, netdev
NetEffect connection manager routines.
Signed-off-by: Glenn Grundstrom <ggrundstrom@neteffect.com>
---
diff -Nurp NULL ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_cm.c
--- NULL 1969-12-31 18:00:00.000000000 -0600
+++ ofa_kernel-1.2/drivers/infiniband/hw/nes/nes_cm.c 2007-08-06 20:09:04.000000000 -0500
@@ -0,0 +1,2847 @@
+/*
+ * Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+
+#define TCPOPT_TIMESTAMP 8
+
+#include <asm/atomic.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/if_arp.h>
+#include <linux/notifier.h>
+#include <linux/net.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/list.h>
+#include <linux/threads.h>
+#include <linux/skbuff.h>
+
+#include <net/neighbour.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+
+#include "nes.h"
+
+static inline int mini_cm_accelerated(struct nes_cm_core *, struct nes_cm_node *);
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *,
+ struct nes_vnic *, struct nes_cm_info *);
+static int mini_cm_del_listen(struct nes_cm_core *, struct nes_cm_listener *);
+
+
+/* External CM API Interface */
+/* instance of function pointers for client API */
+/* set address of this instance to cm_core->cm_ops_p at cm_core alloc */
+struct nes_cm_ops nes_cm_api = {
+ mini_cm_accelerated,
+ mini_cm_listen,
+ mini_cm_del_listen,
+ mini_cm_connect,
+ mini_cm_close,
+ mini_cm_accept,
+ mini_cm_reject,
+ mini_cm_recv_pkt,
+ mini_cm_dealloc_core,
+ mini_cm_get,
+ mini_cm_set
+};
+
+struct nes_cm_core *g_cm_core_p;
+
+atomic_t cm_connects;
+atomic_t cm_accepts;
+atomic_t cm_disconnects;
+atomic_t cm_closes;
+atomic_t cm_connecteds;
+atomic_t cm_connect_reqs;
+atomic_t cm_rejects;
+
+
+/**
+ * create_event
+ */
+static struct nes_cm_event *create_event(struct nes_cm_node *node_p,
+ enum nes_cm_event_type type)
+{
+ struct nes_cm_event *event_p;
+
+ if(!node_p->cm_id)
+ return NULL;
+
+ /* allocate an empty event */
+ event_p = (struct nes_cm_event *)kzalloc(sizeof(struct nes_cm_event),
+ GFP_ATOMIC);
+ if (!event_p)
+ return(NULL);
+
+ event_p->type = type;
+ event_p->node_p = node_p;
+ event_p->cm_info.rem_addr = node_p->rem_addr;
+ event_p->cm_info.loc_addr = node_p->loc_addr;
+ event_p->cm_info.rem_port = node_p->rem_port;
+ event_p->cm_info.loc_port = node_p->loc_port;
+ event_p->cm_info.cm_id = node_p->cm_id;
+
+ dprintk("%s[%u] Created event_p=%p, type=%u, dst_addr=%08x[%x], src_addr=%08x[%x]\n",
+ __FUNCTION__, __LINE__, event_p, type,
+ event_p->cm_info.loc_addr, event_p->cm_info.loc_port,
+ event_p->cm_info.rem_addr, event_p->cm_info.rem_port);
+
+ nes_cm_post_event(event_p);
+ return(event_p);
+}
+
+
+/**
+ * send_mpa_request
+ */
+int send_mpa_request(struct nes_cm_node *node_p)
+{
+ struct sk_buff *skb_p;
+ int ret;
+
+ skb_p = get_free_pkt(node_p);
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ /* send an MPA Request frame */
+ form_cm_frame(skb_p, node_p, NULL, 0, &node_p->mpa_frame_p,
+ node_p->mpa_frame_size, SET_ACK);
+
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 1);
+ if (ret < 0) {
+ return (ret);
+ }
+
+ dprintk("%s[%u] -- \n", __FUNCTION__, __LINE__);
+ return (0);
+}
+
+
+/**
+ * recv_mpa - process a received TCP pkt, we are expecting an
+ * IETF MPA frame
+ */
+static int parse_mpa(struct nes_cm_node *node_p, u8 *buffer, u32 len)
+{
+ struct ietf_mpa_frame *mpa_frame_p;
+
+ dprintk("%s[%u] Enter, node_p=%p\n", __FUNCTION__, __LINE__, node_p);
+ nes_dump_mem(buffer, len);
+
+ /* assume req frame is in tcp data payload */
+ if (len < sizeof(struct ietf_mpa_frame)) {
+ dprintk("The received ietf buffer was too small (%x)\n", len);
+ return (-1);
+ }
+
+ mpa_frame_p = (struct ietf_mpa_frame *)buffer;
+ node_p->mpa_frame_size = (u32)ntohs(mpa_frame_p->priv_data_len);
+
+ if (node_p->mpa_frame_size + sizeof(struct ietf_mpa_frame) != len) {
+ dprintk("The received ietf buffer was not right complete (%x + %x != %x)\n",
+ node_p->mpa_frame_size, (u32)sizeof(struct ietf_mpa_frame), len);
+ return (-1);
+ }
+
+ dprintk("%s[%u] -- recvd MPA Frame - with private data len = %u\n",
+ __FILE__, __LINE__, node_p->mpa_frame_size);
+
+ /* copy entire MPA frame to our node's frame */
+ memcpy(node_p->mpa_frame_b, buffer + sizeof(struct ietf_mpa_frame),
+ node_p->mpa_frame_size);
+ nes_dump_mem(&node_p->mpa_frame_p, node_p->mpa_frame_size);
+ dprintk("%s:%s[%u] -- Exit\n", __FILE__, __FUNCTION__, __LINE__);
+
+ return(0);
+}
+
+
+/**
+ * handle_exception_pkt - process an exception packet.
+ * We have been in a TSA state, and we have now received SW
+ * TCP/IP traffic should be a FIN request or IP pkt with options
+ */
+static int handle_exception_pkt(struct nes_cm_node *node_p,
+ struct sk_buff *skb_p)
+{
+ int ret = 0;
+ struct tcphdr *tcphdr_p = skb_p->h.th;
+
+ /* first check to see if this a FIN pkt */
+ if (tcphdr_p->fin) {
+ /* we need to ACK the FIN request */
+ send_ack(node_p);
+
+ /* check which side we are (client/server) and set next state accordingly */
+ if (node_p->tcp_cntxt.client)
+ node_p->state = NES_CM_STATE_CLOSING;
+ else {
+ /* we are the server side */
+ node_p->state = NES_CM_STATE_CLOSE_WAIT;
+ /* since this is a self contained CM we don't wait for */
+ /* an APP to close us, just send final FIN immediately */
+ ret = send_fin(node_p, NULL);
+ node_p->state = NES_CM_STATE_LAST_ACK;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return(ret);
+}
+
+
+/**
+ * form_cm_frame - get a free packet and build empty frame Use
+ * node info to build.
+ */
+struct sk_buff *form_cm_frame(struct sk_buff *skb_p, struct nes_cm_node *node_p,
+ void *options, u32 optionsize, void *data, u32 datasize, u8 flags)
+{
+ struct tcphdr *tcphdr_p;
+ struct iphdr *iphdr_p;
+ struct ethhdr *ethhdr_p;
+ u8 *buf_p;
+ u16 packetsize = sizeof(*iphdr_p);
+
+ packetsize += sizeof(*tcphdr_p);
+ packetsize += optionsize + datasize;
+
+ memset(skb_p->data, 0x00, ETH_HLEN + sizeof(*iphdr_p) + sizeof(*tcphdr_p));
+
+ skb_p->len = 0;
+ buf_p = skb_put(skb_p, packetsize + ETH_HLEN);
+
+ ethhdr_p = (struct ethhdr *) buf_p;
+ buf_p += ETH_HLEN;
+
+ iphdr_p = skb_p->nh.iph = (struct iphdr *)buf_p;
+ buf_p += sizeof(*iphdr_p);
+
+ tcphdr_p = skb_p->h.th = (struct tcphdr *) buf_p;
+ buf_p += sizeof(*tcphdr_p);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
+ skb_p->ip_summed = CHECKSUM_HW;
+#else
+ skb_p->ip_summed = CHECKSUM_PARTIAL;
+#endif
+ skb_p->protocol = ntohs(0x800);
+ skb_p->data_len = 0;
+ skb_p->mac.raw = skb_p->data;
+ skb_p->mac_len = ETH_HLEN;
+
+ memcpy(ethhdr_p->h_dest, node_p->rem_mac, ETH_ALEN);
+ memcpy(ethhdr_p->h_source, node_p->loc_mac, ETH_ALEN);
+ ethhdr_p->h_proto = htons(0x0800);
+
+ iphdr_p->version = IPVERSION;
+ iphdr_p->ihl = 5; /* 5 * 4Byte words, IP headr len */
+ iphdr_p->tos = 0;
+ iphdr_p->tot_len = htons(packetsize);
+ iphdr_p->id = htons(++node_p->tcp_cntxt.loc_id);
+
+ iphdr_p->frag_off = ntohs(0x4000);
+ iphdr_p->ttl = 0x40;
+ iphdr_p->protocol= 0x06; /* IPPROTO_TCP */
+
+ iphdr_p->saddr = htonl(node_p->loc_addr);
+ iphdr_p->daddr = htonl(node_p->rem_addr);
+
+ tcphdr_p->source = htons(node_p->loc_port);
+ tcphdr_p->dest = htons(node_p->rem_port);
+ tcphdr_p->seq = htonl(node_p->tcp_cntxt.loc_seq_num);
+
+ if (flags & SET_ACK) {
+ node_p->tcp_cntxt.loc_ack_num = node_p->tcp_cntxt.rcv_nxt;
+ tcphdr_p->ack_seq = htonl(node_p->tcp_cntxt.loc_ack_num);
+ tcphdr_p->ack = 1;
+ } else
+ tcphdr_p->ack_seq = 0;
+
+ if (flags & SET_SYN) {
+ node_p->tcp_cntxt.loc_seq_num ++;
+ tcphdr_p->syn = 1;
+ } else
+ node_p->tcp_cntxt.loc_seq_num += datasize; /* data (no headers) */
+
+ dprintk("%s[%u] Local seq # now %x\n", __FUNCTION__, __LINE__,
+ node_p->tcp_cntxt.loc_seq_num);
+ if (flags & SET_FIN)
+ tcphdr_p->fin = 1;
+
+ if (flags & SET_RST)
+ tcphdr_p->rst = 1;
+
+ tcphdr_p->doff = (u16) ((sizeof(*tcphdr_p) + optionsize + 3)>> 2);
+ tcphdr_p->window = htons(node_p->tcp_cntxt.rcv_wnd);
+ tcphdr_p->urg_ptr = 0;
+ if (optionsize)
+ memcpy(buf_p, options, optionsize);
+ buf_p += optionsize;
+ if (datasize)
+ memcpy(buf_p, data, datasize);
+
+ skb_shinfo(skb_p)->nr_frags = 0;
+
+ return(skb_p);
+}
+
+
+/**
+ * dump_pkt
+ */
+static void dump_pkt(struct sk_buff *skb_p)
+{
+ u8 *pkt_p;
+
+ if (!skb_p)
+ return;
+
+ pkt_p = (u8 *)skb_p->data;
+ /* dprintk("skb_p->head=%p, data=%p, tail=%p, end=%p,"
+ "skb_p->len=%u, data_len=%u\n",
+ skb_p->head, skb_p->data, skb_p->tail, skb_p->end,
+ skb_p->len, skb_p->data_len);
+ */
+ nes_dump_mem(pkt_p, skb_p->len);
+
+ return;
+}
+
+
+/**
+ * print_core - dump a cm core
+ */
+static void print_core(struct nes_cm_core *core_p)
+{
+ dprintk("---------------------------------------------\n");
+ dprintk("CM Core -- (core_p = %p )\n", core_p);
+ if (!core_p)
+ return;
+ dprintk("---------------------------------------------\n");
+ dprintk("Session ID : %u \n", atomic_read(&core_p->session_id));
+
+ dprintk("State : %u \n", core_p->state);
+
+ dprintk("Tx Free cnt : %u \n", skb_queue_len(&core_p->tx_free_list));
+ dprintk("Listen Nodes : %u \n", atomic_read(&core_p->listen_node_cnt));
+ dprintk("Active Nodes : %u \n", atomic_read(&core_p->node_cnt));
+
+ dprintk("core_p : %p \n", core_p);
+
+ dprintk("-------------- end core ---------------\n");
+ return;
+}
+
+
+/**
+ * schedule_nes_timer
+ */
+int schedule_nes_timer(struct nes_cm_node *node_p, struct sk_buff *skb_p,
+ enum nes_timer_type type, int send_retrans)
+{
+ unsigned long flags;
+ struct nes_cm_core *core_p;
+ struct nes_timer_entry *new_send;
+ int ret = 0;
+ u32 was_timer_set;
+
+ new_send = kzalloc(sizeof(struct nes_timer_entry), GFP_ATOMIC);
+ if(!new_send)
+ return -1;
+ /* new_send->timetosend = currenttime */
+ new_send->retrycount = NES_DEFAULT_RETRYS;
+ new_send->retranscount = NES_DEFAULT_RETRANS;
+ new_send->skb = skb_p;
+ new_send->timetosend = jiffies;
+ new_send->type = type;
+ new_send->netdev = node_p->netdev_p;
+ new_send->send_retrans = send_retrans;
+
+ if(type == NES_TIMER_TYPE_CLOSE) {
+ dprintk("Scheduling Close: node_p = %p, new_send = %p.\n", node_p, new_send);
+ new_send->timetosend += (HZ/2); /* TODO: decide on the correct value here */
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ list_add_tail(&new_send->list, &node_p->recv_list);
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+ }
+
+ if(type == NES_TIMER_TYPE_SEND) {
+ dprintk("Sending Packet %p:\n", new_send);
+ new_send->seq_num = htonl(skb_p->h.th->seq);
+ dump_pkt(skb_p);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ list_add_tail(&new_send->list, &node_p->retrans_list);
+ spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
+ }
+ if(type == NES_TIMER_TYPE_RECV) {
+ new_send->seq_num = htonl(skb_p->h.th->seq);
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ list_add_tail(&new_send->list, &node_p->recv_list);
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+ }
+ core_p = node_p->core_p;
+
+ was_timer_set = timer_pending(&core_p->tcp_timer);
+
+ if(!was_timer_set || time_before(new_send->timetosend,
+ core_p->tcp_timer.expires)){
+ if(was_timer_set) {
+ del_timer(&core_p->tcp_timer);
+ }
+ core_p->tcp_timer.expires = new_send->timetosend;
+
+ add_timer(&core_p->tcp_timer);
+ }
+ return(ret);
+}
+
+
+/**
+ * nes_cm_timer_tick
+ */
+void nes_cm_timer_tick(unsigned long pass)
+{
+ unsigned long flags, qplockflags;
+ unsigned long nexttimeout = jiffies + NES_LONG_TIME;
+ struct iw_cm_id *cm_id;
+ struct nes_cm_node *node_p;
+ struct nes_timer_entry *send_entry, *recv_entry;
+ struct list_head *list_p_core, *list_p_core_temp, *list_p_node_temp, *list_p_node;
+ struct nes_cm_core *core_p = g_cm_core_p;
+ struct nes_qp *nesqp;
+ u32 settimer = 0;
+ int ret = NETDEV_TX_OK;
+
+ list_for_each_safe(list_p_node, list_p_core_temp, &core_p->connected_nodes) {
+ node_p = container_of(list_p_node, struct nes_cm_node, list);
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ list_for_each_safe(list_p_core, list_p_node_temp, &node_p->recv_list) {
+ recv_entry = container_of(list_p_core, struct nes_timer_entry, list);
+ if ((time_after(recv_entry->timetosend, jiffies)) &&
+ (recv_entry->type == NES_TIMER_TYPE_CLOSE)) {
+ if(nexttimeout > recv_entry->timetosend || !settimer) {
+ nexttimeout = recv_entry->timetosend;
+ settimer = 1;
+ }
+ continue;
+ }
+ list_del(&recv_entry->list);
+ cm_id = node_p->cm_id;
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+ if(recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+ nesqp = (struct nes_qp *)recv_entry->skb;
+ cm_id->rem_ref(cm_id);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with something to do!!! ******\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ nesqp->ibqp_state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with nothing to do!!! ******\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ }
+ else if(recv_entry->type == NES_TIMER_TYPE_RECV) {
+ dprintk("Processing Packet (%p):\n", recv_entry->skb->data);
+ dump_pkt(recv_entry->skb);
+ process_packet(node_p, recv_entry->skb, core_p);
+ dev_kfree_skb_any(recv_entry->skb);
+ }
+ kfree(recv_entry);
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ list_for_each_safe(list_p_core, list_p_node_temp, &node_p->retrans_list) {
+ send_entry = container_of(list_p_core, struct nes_timer_entry, list);
+ if(time_after(send_entry->timetosend, jiffies)) {
+ if(nexttimeout > send_entry->timetosend || !settimer) {
+ nexttimeout = send_entry->timetosend;
+ settimer = 1;
+ }
+ continue;
+ }
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
+ if(send_entry->type == NES_TIMER_NODE_CLEANUP){
+ dprintk("!send - %p-> next/prev=%p,%p, tts=%lx, skb=%p, type=%x,"
+ " retry=%x, retrans=%x, context=%x, seq=%x\n",
+ send_entry, send_entry->list.next, send_entry->list.prev,
+ send_entry->timetosend, send_entry->skb, send_entry->type,
+ send_entry->retrycount, send_entry->retranscount,
+ send_entry->context, send_entry->seq_num);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ continue;
+ }
+ if(send_entry->seq_num < node_p->tcp_cntxt.rem_ack_num ||
+ node_p->accelerated) {
+ dev_kfree_skb_any(send_entry->skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ continue;
+ }
+
+ if(!send_entry->retranscount || !send_entry->retrycount) {
+ dev_kfree_skb_any(send_entry->skb);
+ kfree(send_entry);
+ create_event(node_p, NES_CM_EVENT_ABORTED);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ continue;
+ }
+ atomic_inc(&send_entry->skb->users);
+ ret = nes_nic_cm_xmit(send_entry->skb, node_p->netdev_p);
+ if(ret != NETDEV_TX_OK) {
+ atomic_dec(&send_entry->skb->users);
+ send_entry->retrycount--;
+ nexttimeout = jiffies + NES_SHORT_TIME;
+ settimer = 1;
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ list_add(&send_entry->list, &node_p->retrans_list);
+ break;
+ }
+ dprintk("Packet Sent:\n");
+ dump_pkt(send_entry->skb);
+ if(send_entry->send_retrans) {
+ send_entry->retranscount--;
+ send_entry->timetosend = jiffies + NES_RETRY_TIMEOUT;
+ if(nexttimeout > send_entry->timetosend || !settimer) {
+ nexttimeout = send_entry->timetosend;
+ settimer = 1;
+ }
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ list_add(&send_entry->list, &node_p->retrans_list);
+ continue;
+ }
+ else {
+ dev_kfree_skb_any(send_entry->skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ continue;
+ }
+ }
+ spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
+
+ if(ret != NETDEV_TX_OK)
+ break;
+ }
+
+ if(settimer)
+ {
+ if(timer_pending(&core_p->tcp_timer)) {
+ del_timer(&core_p->tcp_timer);
+ }
+ core_p->tcp_timer.expires = nexttimeout;
+ add_timer(&core_p->tcp_timer);
+ }
+}
+
+
+/**
+ * send_syn
+ */
+int send_syn(struct nes_cm_node *node_p, u32 sendack)
+{
+ int ret;
+ int flags = SET_SYN;
+ struct sk_buff *skb_p;
+ char optionsbuffer[sizeof(struct option_mss) +
+ sizeof(struct option_windowscale) +
+ sizeof(struct option_base) + 1];
+
+ int optionssize = 0;
+ /* Sending MSS option */
+ union all_known_options *options;
+
+ if (!node_p)
+ return(-EINVAL);
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_mss.optionnum = OPTION_NUMBER_MSS;
+ options->as_mss.length = sizeof(struct option_mss);
+ options->as_mss.mss = htons(node_p->tcp_cntxt.mss);
+ optionssize += sizeof(struct option_mss);
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_windowscale.optionnum = OPTION_NUMBER_WINDOW_SCALE;
+ options->as_windowscale.length = sizeof(struct option_windowscale);
+ options->as_windowscale.shiftcount = 2;
+ optionssize += sizeof(struct option_windowscale);
+
+ if(sendack && !(NES_DRV_OPT_SUPRESS_OPTION_BC & nes_drv_opt)) {
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_base.optionnum = OPTION_NUMBER_WRITE0;
+ options->as_base.length = sizeof(struct option_base);
+ optionssize += sizeof(struct option_base);
+ /* we need the size to be a multiple of 4 */
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = 1;
+ optionssize += 1;
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = 1;
+ optionssize += 1;
+ }
+
+ options = (union all_known_options *)&optionsbuffer[optionssize];
+ options->as_end = OPTION_NUMBER_END;
+ optionssize += 1;
+
+ dprintk("%s: Enter\n", __FUNCTION__);
+
+ skb_p = get_free_pkt(node_p);
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",__FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ if (sendack)
+ flags |= SET_ACK;
+
+ form_cm_frame(skb_p, node_p, optionsbuffer, optionssize, NULL, 0, flags);
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 1);
+
+ return(ret);
+}
+
+
+/**
+ * send_reset
+ */
+int send_reset(struct nes_cm_node *node_p)
+{
+ int ret;
+ struct sk_buff *skb_p = get_free_pkt(node_p);
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ form_cm_frame(skb_p, node_p, NULL, 0, NULL, 0, SET_RST);
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 0);
+
+ return(ret);
+}
+
+
+/**
+ * send_ack
+ */
+int send_ack(struct nes_cm_node *node_p)
+{
+ int ret;
+ struct sk_buff *skb_p = get_free_pkt(node_p);
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ form_cm_frame(skb_p, node_p, NULL, 0, NULL, 0, SET_ACK);
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 0);
+
+ return(ret);
+}
+
+
+/**
+ * send_fin
+ */
+int send_fin(struct nes_cm_node *node_p, struct sk_buff *skb_p)
+{
+ int ret;
+
+ /* if we didn't get a frame get one */
+ if (!skb_p)
+ skb_p = get_free_pkt(node_p);
+
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ form_cm_frame(skb_p, node_p, NULL, 0, NULL, 0, SET_ACK | SET_FIN);
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 1);
+
+ return(ret);
+}
+
+
+/**
+ * get_free_pkt
+ */
+struct sk_buff *get_free_pkt(struct nes_cm_node *node_p)
+{
+ struct sk_buff *skb_p, *new_skb_p;
+
+ /* check to see if we need to repopulate the free tx pkt queue */
+ if (skb_queue_len(&node_p->core_p->tx_free_list) < NES_CM_FREE_PKT_LO_WATERMARK) {
+ while (skb_queue_len(&node_p->core_p->tx_free_list) <
+ node_p->core_p->free_tx_pkt_max) {
+ /* replace the frame we took, we won't get it back */
+ new_skb_p = dev_alloc_skb(node_p->core_p->mtu);
+
+ /* add a replacement frame to the free tx list head */
+ skb_queue_head(&node_p->core_p->tx_free_list, new_skb_p);
+ }
+ }
+
+ skb_p = skb_dequeue(&node_p->core_p->tx_free_list);
+ return(skb_p);
+}
+
+
+/**
+ * make_hashkey - generate hash key from node tuple
+ */
+static inline int make_hashkey(u16 loc_port, nes_addr_t loc_addr, u16 rem_port,
+ nes_addr_t rem_addr)
+{
+ u32 hashkey = 0;
+
+ hashkey = loc_addr + rem_addr + loc_port + rem_port;
+ hashkey = (hashkey % NES_CM_HASHTABLE_SIZE);
+
+ return(hashkey);
+}
+
+
+/**
+ * find_node - find a cm node that matches the reference cm node
+ */
+static struct nes_cm_node * find_node(struct nes_cm_core *core_p,
+ u16 rem_port, nes_addr_t rem_addr, u16 loc_port, nes_addr_t loc_addr)
+{
+ u32 hashkey;
+ struct list_head *list_p;
+ struct list_head *hte_p;
+ struct nes_cm_node *node_p;
+
+ /* make a hash index key for this packet */
+ hashkey = make_hashkey(loc_port, loc_addr, rem_port, rem_addr);
+
+ /* get a handle on the hte */
+
+ hte_p = &core_p->connected_nodes;
+
+ dprintk("%s[%u] -- Searching for an owner node:%x:%x from core %p->%p\n",
+ __FILE__, __LINE__, loc_addr, loc_port, core_p, hte_p);
+
+ /* walk list and find cm_node associated with this session ID */
+ list_for_each(list_p, hte_p)
+ {
+ node_p = container_of(list_p, struct nes_cm_node, list);
+ /* compare quad, return node handle if a match */
+ dprintk("finding node %x:%x =? %x:%x ^ %x:%x =? %x:%x\n",
+ node_p->loc_addr, node_p->loc_port,
+ loc_addr, loc_port,
+ node_p->rem_addr, node_p->rem_port,
+ rem_addr, rem_port);
+ if ((node_p->loc_addr == loc_addr) && (node_p->loc_port == loc_port) &&
+ (node_p->rem_addr == rem_addr) && (node_p->rem_port == rem_port)) {
+ return(node_p);
+ }
+ }
+
+ /* no owner node */
+ return(NULL);
+}
+
+
+/**
+ * find_listener - find a cm node listening on this addr-port pair
+ */
+static struct nes_cm_listener * find_listener(struct nes_cm_core *core_p,
+ nes_addr_t dst_addr, u16 dst_port)
+{
+ int flags;
+ struct list_head *list_p;
+ struct nes_cm_listener *listen_node_p;
+
+ /* walk list and find cm_node associated with this session ID */
+ spin_lock_irqsave(&core_p->listen_list_lock, flags);
+ list_for_each(list_p, &core_p->listen_list.list) {
+ listen_node_p = container_of(list_p, struct nes_cm_listener, list);;
+ /* compare node pair, return node handle if a match */
+ if (((listen_node_p->loc_addr == dst_addr) ||
+ listen_node_p->loc_addr == 0x00000000) &&
+ (listen_node_p->loc_port == dst_port)) {
+ atomic_inc(&listen_node_p->ref_count);
+ spin_unlock_irqrestore(&core_p->listen_list_lock, flags);
+ return(listen_node_p);
+ }
+ }
+ spin_unlock_irqrestore(&core_p->listen_list_lock, flags);
+ dprintk("Unable to find listener- %x:%x\n",
+ dst_addr, dst_port);
+
+ /* no listener */
+ return(NULL);
+}
+
+
+/**
+ * add_hte_node - add a cm node to the hash table
+ */
+static int add_hte_node(struct nes_cm_core *core_p, struct nes_cm_node *node_p)
+{
+ unsigned long flags;
+ u32 hashkey;
+ struct list_head *hte_p;
+
+ if (!node_p || !core_p)
+ return(-EINVAL);
+
+ dprintk("%s:%s[%u] -- Adding Node to Active Connection HT\n",
+ __FILE__, __FUNCTION__, __LINE__);
+
+ /* first, make an index into our hash table */
+ hashkey = make_hashkey(node_p->loc_port, node_p->loc_addr,
+ node_p->rem_port, node_p->rem_addr);
+ node_p->hashkey = hashkey;
+
+ spin_lock_irqsave(&core_p->ht_lock, flags);
+
+ /* get a handle on the hash table element (list head for this slot) */
+ hte_p = &core_p->connected_nodes;
+ list_add_tail(&node_p->list, hte_p);
+ atomic_inc(&core_p->ht_node_cnt);
+
+ spin_unlock_irqrestore(&core_p->ht_lock, flags);
+
+ return(0);
+}
+
+
+/**
+ * del_hte_node - delete a cm node from the hash table
+ */
+int del_hte_node(struct nes_cm_core *core_p, struct nes_cm_node *node_p)
+{
+ unsigned long flags;
+
+ if (!node_p)
+ return(-EINVAL);
+ dprintk("%s[%u] -- (%p, %p)\n", __FILE__, __LINE__, core_p, node_p);
+
+ spin_lock_irqsave(&node_p->core_p->ht_lock, flags);
+ list_del(&node_p->list);
+ spin_unlock_irqrestore(&node_p->core_p->ht_lock, flags);
+
+ atomic_dec(&core_p->ht_node_cnt);
+ dprintk("%s[%u] -- \n", __FILE__,__LINE__);
+
+ return(0);
+}
+
+
+/**
+ * mini_cm_del_listen
+ */
+static int mini_cm_del_listen(struct nes_cm_core *core_p,
+ struct nes_cm_listener *node_p)
+{
+ int ret = 1;
+ struct nes_vnic *nesvnic;
+ struct iw_cm_id *cm_id;
+ int flags;
+
+ spin_lock_irqsave(&core_p->listen_list_lock, flags);
+ if(!atomic_dec_return(&node_p->ref_count)) {
+ list_del(&node_p->list);
+
+ /* decrement our listen node count */
+ atomic_dec(&core_p->listen_node_cnt);
+
+ spin_unlock_irqrestore(&core_p->listen_list_lock, flags);
+
+ cm_id = node_p->cm_id;
+ if(cm_id && cm_id->device) {
+ nesvnic = to_nesvnic(cm_id->device);
+ if (nesvnic) {
+ nes_manage_apbvt(nesvnic, node_p->loc_port,
+ PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+ }
+ }
+ dprintk("%s[%u] -- \n",__FILE__,__LINE__);
+ kfree(node_p);
+ ret = 0;
+ } else {
+ spin_unlock_irqrestore(&core_p->listen_list_lock, flags);
+ }
+ return(ret);
+}
+
+
+/**
+ * mini_cm_accelerated
+ */
+static inline int mini_cm_accelerated(struct nes_cm_core *core_p,
+ struct nes_cm_node *node_p)
+{
+ u32 was_timer_set;
+ node_p->accelerated = 1;
+ was_timer_set = timer_pending(&core_p->tcp_timer);
+ if(!was_timer_set){
+ core_p->tcp_timer.expires = jiffies + NES_SHORT_TIME;
+ add_timer(&core_p->tcp_timer);
+ }
+ return(0);
+}
+
+
+/**
+ * make_cm_node - create a new instance of a cm node
+ */
+static struct nes_cm_node *make_cm_node(struct nes_cm_core *core_p,
+ struct nes_vnic *nesvnic, struct nes_cm_info *nfo_p,
+ struct nes_cm_listener *listen_p)
+{
+ struct nes_cm_node *node_p;
+ struct timespec ts;
+ int arpindex = 0;
+ struct nes_device *nesdev;
+ struct nes_adapter *nesadapter;
+
+ /* create an hte and cm_node for this instance */
+ node_p = (struct nes_cm_node *)kzalloc(sizeof(*node_p), GFP_ATOMIC);
+ if (!node_p)
+ return NULL;
+
+ memset(node_p, 0, sizeof(struct nes_cm_node));
+ /* set our node specific transport info */
+ node_p->loc_addr = nfo_p->loc_addr;
+ node_p->rem_addr = nfo_p->rem_addr;
+ node_p->loc_port = nfo_p->loc_port;
+ node_p->rem_port = nfo_p->rem_port;
+ node_p->send_write0 = send_first;
+ dprintk("Make node addresses : loc = %x:%x, rem = %x:%x\n",
+ node_p->loc_addr, node_p->loc_port, node_p->rem_addr, node_p->rem_port);
+ node_p->listen_p = listen_p;
+ node_p->netdev_p = nesvnic->netdev;
+ node_p->cm_id = nfo_p->cm_id;
+ memcpy(node_p->loc_mac, nesvnic->netdev->dev_addr, ETH_ALEN);
+
+ INIT_LIST_HEAD(&node_p->retrans_list);
+ spin_lock_init(&node_p->retrans_list_lock);
+ INIT_LIST_HEAD(&node_p->recv_list);
+ spin_lock_init(&node_p->recv_list_lock);
+
+ node_p->loopbackpartner = NULL;
+ atomic_set(&node_p->ref_count, 1);
+ node_p->listener = NULL;
+ /* associate our parent CM core */
+ node_p->core_p = core_p;
+ node_p->tcp_cntxt.loc_id = NES_CM_DEF_LOCAL_ID;
+ node_p->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND;
+ ts = current_kernel_time();
+ node_p->tcp_cntxt.loc_seq_num = cpu_to_le32(htonl(ts.tv_nsec));
+ node_p->tcp_cntxt.mss = nesvnic->max_frame_size - sizeof(struct iphdr) -
+ sizeof(struct tcphdr) - ETH_HLEN;
+ dprintk("%s: Setting MSS to %u.\n",__FUNCTION__, node_p->tcp_cntxt.mss);
+ node_p->tcp_cntxt.rcv_nxt = 0;
+ /* get a unique session ID , add thread_id to an upcounter to handle race */
+ atomic_inc(&core_p->node_cnt);
+ atomic_inc(&core_p->session_id);
+ node_p->session_id = (u32)(atomic_read(&core_p->session_id) + current->tgid);
+ node_p->conn_type = nfo_p->conn_type;
+
+ /* get some device handles, for arp lookup */
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+
+ /* get the mac addr for the remote node */
+ arpindex = nes_arp_table(nesdev, node_p->rem_addr, NULL, NES_ARP_RESOLVE);
+ if (arpindex < 0) {
+ dprintk("%s[%d] -- IP addr %x NOT found in ARP table\n",
+ __FILE__, __LINE__, node_p->rem_addr);
+ kfree(node_p);
+ return(NULL);
+ }
+
+ /* copy the mac addr to node context */
+ memcpy(node_p->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN);
+ dprintk("%s[%u] -- Remote mac addr from arp table:%02x, %02x, %02x, %02x, %02x, %02x\n",
+ __FILE__, __LINE__,
+ node_p->rem_mac[0], node_p->rem_mac[1],
+ node_p->rem_mac[2], node_p->rem_mac[3],
+ node_p->rem_mac[4], node_p->rem_mac[5]);
+
+ add_hte_node(core_p, node_p);
+
+ return(node_p);
+}
+
+
+/**
+ * destroy_cm_node - destroy an instance of a cm node
+ */
+static int destroy_cm_node(struct nes_cm_core *core_p,
+ struct nes_cm_node *node_p)
+{
+ unsigned long flags, qplockflags;
+ struct nes_timer_entry *send_entry;
+ struct nes_timer_entry *recv_entry;
+ struct iw_cm_id *cm_id;
+ struct list_head *list_p_core, *list_p_node_temp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+
+ if (!node_p)
+ return(-EINVAL);
+ del_hte_node(core_p, node_p);
+
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ list_for_each_safe(list_p_core, list_p_node_temp, &node_p->retrans_list) {
+ send_entry = container_of(list_p_core, struct nes_timer_entry, list);
+ list_del(&send_entry->list);
+ spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
+ dev_kfree_skb_any(send_entry->skb);
+ kfree(send_entry);
+ spin_lock_irqsave(&node_p->retrans_list_lock, flags);
+ continue;
+ }
+ spin_unlock_irqrestore(&node_p->retrans_list_lock, flags);
+
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ list_for_each_safe(list_p_core, list_p_node_temp, &node_p->recv_list) {
+ recv_entry = container_of(list_p_core, struct nes_timer_entry, list);
+ list_del(&recv_entry->list);
+ cm_id = node_p->cm_id;
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+ if(recv_entry->type == NES_TIMER_TYPE_CLOSE) {
+ nesqp = (struct nes_qp *)recv_entry->skb;
+ cm_id->rem_ref(cm_id);
+ spin_lock_irqsave(&nesqp->lock, qplockflags);
+ if (nesqp->cm_id) {
+ dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with something to do!!! ******\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
+ nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
+ nesqp->last_aeq = NES_AEQE_AEID_RESET_SENT;
+ nesqp->ibqp_state = IB_QPS_ERR;
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ nes_cm_disconn(nesqp);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, qplockflags);
+ dprintk("%s: QP%u: cm_id = %p: ****** HIT A NES_TIMER_TYPE_CLOSE"
+ " with nothing to do!!! ******\n",
+ __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ }
+ else if(recv_entry->type == NES_TIMER_TYPE_RECV) {
+ dev_kfree_skb_any(recv_entry->skb);
+ }
+ kfree(recv_entry);
+ spin_lock_irqsave(&node_p->recv_list_lock, flags);
+ }
+ spin_unlock_irqrestore(&node_p->recv_list_lock, flags);
+
+ if(node_p->listen_p) {
+ mini_cm_del_listen(core_p, node_p->listen_p);
+ }
+ else {
+ cm_id = node_p->cm_id;
+ if(cm_id && cm_id->device) {
+ nesvnic = to_nesvnic(cm_id->device);
+ if (nesvnic) {
+ nes_manage_apbvt(nesvnic, node_p->loc_port,
+ PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_DEL);
+ }
+ }
+ }
+ if(!atomic_dec_return(&node_p->ref_count)) {
+ kfree(node_p);
+ atomic_dec(&core_p->node_cnt);
+ }
+ return(0);
+}
+
+
+/**
+ * process_options
+ */
+static void process_options(struct nes_cm_node *node_p, u8 *optionsloc, u32 optionsize)
+{
+ u32 tmp;
+ u32 offset = 0;
+ union all_known_options *all_options;
+
+ while(offset < optionsize)
+ {
+ all_options = (union all_known_options *)(optionsloc + offset);
+ switch(all_options->as_base.optionnum)
+ {
+ case OPTION_NUMBER_END:
+ offset = optionsize;
+ break;
+ case OPTION_NUMBER_NONE:
+ offset += 1;
+ continue;
+ case OPTION_NUMBER_MSS:
+ tmp = htons(all_options->as_mss.mss);
+ if(tmp < node_p->tcp_cntxt.mss)
+ node_p->tcp_cntxt.mss = tmp;
+ break;
+ case OPTION_NUMBER_WINDOW_SCALE:
+ node_p->tcp_cntxt.snd_wscale = all_options->as_windowscale.shiftcount;
+ node_p->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
+ node_p->tcp_cntxt.rcv_wnd = NES_CM_DEFAULT_RCV_WND_SCALED >>
+ NES_CM_DEFAULT_RCV_WND_SCALE;
+ break;
+ case OPTION_NUMBER_WRITE0:
+ node_p->send_write0 = 1;
+ break;
+ default:
+ dprintk("TCP Option not understood: %x\n", all_options->as_base.optionnum);
+ break;
+ }
+ offset += all_options->as_base.length;
+ }
+}
+
+
+/**
+ * process_packet
+ */
+int process_packet(struct nes_cm_node *node_p, struct sk_buff *skb_p,
+ struct nes_cm_core *core_p)
+{
+ int optionsize;
+ int datasize;
+ int ret = 0;
+ struct tcphdr *tcphdr_p = skb_p->h.th;
+ u32 inc_sequence;
+
+ if(!tcphdr_p)
+ return -1;
+
+ if (tcphdr_p->rst) {
+ dprintk("%s[%u] Received Reset, node_p = %p, state = %u.\n",
+ __FUNCTION__, __LINE__, node_p, node_p->state);
+ switch(node_p->state) {
+ case NES_CM_STATE_TSA:
+ case NES_CM_STATE_CLOSED:
+ break;
+ case NES_CM_STATE_LISTENING:
+ case NES_CM_STATE_SYN_RCVD:
+ mini_cm_close(core_p, node_p);
+ break;
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_MPAREQ_SENT:
+ default:
+ // create event
+ node_p->state = NES_CM_STATE_CLOSED;
+ create_event(node_p, NES_CM_EVENT_ABORTED);
+ break;
+
+ }
+ return -1;
+ }
+
+ optionsize = (tcphdr_p->doff << 2) - sizeof(struct tcphdr);
+
+ skb_pull(skb_p, skb_p->nh.iph->ihl << 2);
+ skb_pull(skb_p, tcphdr_p->doff << 2);
+
+ datasize = skb_p->len;
+ inc_sequence = ntohl(tcphdr_p->seq);
+
+ if (!tcphdr_p->syn && (inc_sequence != node_p->tcp_cntxt.rcv_nxt)) {
+ return (-1);
+ }
+
+ node_p->tcp_cntxt.rcv_nxt = inc_sequence + datasize;
+ node_p->tcp_cntxt.snd_wnd = htons(tcphdr_p->window) <<
+ node_p->tcp_cntxt.snd_wscale;
+
+ if (node_p->tcp_cntxt.snd_wnd > node_p->tcp_cntxt.max_snd_wnd) {
+ node_p->tcp_cntxt.max_snd_wnd = node_p->tcp_cntxt.snd_wnd;
+ }
+
+ if (optionsize) {
+ u8 *optionsloc = (u8 *) &tcphdr_p[1];
+ process_options(node_p, optionsloc, optionsize);
+ }
+
+ if (tcphdr_p->ack) {
+ node_p->tcp_cntxt.rem_ack_num = ntohl(tcphdr_p->ack_seq);
+ switch (node_p->state) {
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ /* read and stash current sequence number */
+ if (node_p->tcp_cntxt.rem_ack_num > node_p->tcp_cntxt.loc_seq_num) {
+ dprintk("ERROR - node_p->tcp_cntxt.rem_ack_num >"
+ " node_p->tcp_cntxt.loc_seq_num\n");
+ send_reset(node_p);
+ return (0);
+ }
+ if (node_p->conn_type == NES_CM_IWARP_CONN_TYPE) {
+ if (node_p->state == NES_CM_STATE_SYN_SENT)
+ node_p->state = NES_CM_STATE_ONE_SIDE_ESTABLISHED;
+ else
+ node_p->state = NES_CM_STATE_ESTABLISHED;
+ } else {
+ create_event(node_p, NES_CM_EVENT_MPA_REQ);
+ /* we are done handling this state, set node to a TSA state */
+ node_p->state = NES_CM_STATE_TSA;
+ }
+ break;
+ case NES_CM_STATE_LAST_ACK:
+ node_p->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ node_p->state = NES_CM_STATE_FIN_WAIT2;
+ break;
+ case NES_CM_STATE_CLOSING:
+ node_p->state = NES_CM_STATE_TIME_WAIT;
+ /* need to schedule this to happen in 2MSL timeouts */
+ node_p->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_MPAREQ_SENT:
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_TIME_WAIT:
+ case NES_CM_STATE_CLOSED:
+ break;
+ case NES_CM_STATE_LISTENING:
+ if (!(tcphdr_p->syn)) {
+ dprintk("Received an ack without a SYN on a listening port\n");
+ destroy_cm_node(core_p, node_p);
+ } else {
+ dprintk("Received an ack on a listening port (syn-ack maybe?)\n");
+ }
+ break;
+ case NES_CM_STATE_TSA:
+ dprintk("Received a packet while in TSA state\n");
+ break;
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_FIN_WAIT2:
+ default:
+ dprintk("Received ack from unknown state: %x\n", node_p->state);
+ send_reset(node_p);
+ break;
+ }
+ }
+
+ if (tcphdr_p->syn) {
+ if (datasize == 0)
+ node_p->tcp_cntxt.rcv_nxt ++;
+
+ dprintk("%s: Received SYN\n", __FUNCTION__);
+ if (node_p->state == NES_CM_STATE_LISTENING) {
+ node_p->state = NES_CM_STATE_SYN_RCVD;
+ send_syn(node_p, 1);
+ dprintk("%s:%s[%u] -- Sent syn_ack\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ }
+ if (node_p->state == NES_CM_STATE_ONE_SIDE_ESTABLISHED) {
+ node_p->state = NES_CM_STATE_ESTABLISHED;
+ /* send final handshake ACK */
+ ret = send_ack(node_p);
+ if (ret < 0)
+ return (ret);
+
+ if (node_p->conn_type == NES_CM_IWARP_CONN_TYPE) {
+ node_p->state = NES_CM_STATE_MPAREQ_SENT;
+ ret = send_mpa_request(node_p);
+ if (ret < 0)
+ return (ret);
+ } else {
+ create_event(node_p, NES_CM_EVENT_CONNECTED);
+ node_p->state = NES_CM_STATE_TSA;
+ }
+ }
+ }
+
+ if (tcphdr_p->fin) {
+ dprintk("%s: Received FIN\n", __FUNCTION__);
+ node_p->tcp_cntxt.rcv_nxt++;
+ switch (node_p->state) {
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_MPAREQ_SENT:
+ node_p->state = NES_CM_STATE_CLOSE_WAIT;
+ node_p->state = NES_CM_STATE_LAST_ACK;
+ ret = send_fin(node_p, NULL);
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ node_p->state = NES_CM_STATE_CLOSING;
+ ret = send_ack(node_p);
+ break;
+ case NES_CM_STATE_FIN_WAIT2:
+ node_p->state = NES_CM_STATE_TIME_WAIT;
+ node_p->tcp_cntxt.loc_seq_num ++;
+ ret = send_ack(node_p);
+ /* need to schedule this to happen in 2MSL timeouts */
+ node_p->state = NES_CM_STATE_CLOSED;
+ break;
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_CLOSING:
+ case NES_CM_STATE_TSA:
+ default:
+ dprintk(KERN_INFO PFX "Received a fin while in %x state\n",
+ node_p->state);
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (datasize) {
+ u8 *dataloc = skb_p->data;
+ /* figure out what state we are in and handle transition to next state */
+ switch (node_p->state) {
+ case NES_CM_STATE_LISTENING:
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_FIN_WAIT1:
+ case NES_CM_STATE_FIN_WAIT2:
+ case NES_CM_STATE_CLOSE_WAIT:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_CLOSING:
+ break;
+ case NES_CM_STATE_MPAREQ_SENT:
+ /* recv the mpa res frame, ret=frame len (incl priv data) */
+ ret = parse_mpa(node_p, dataloc, datasize);
+ if (ret < 0)
+ break;
+ /* set the req frame payload len in skb */
+ /* we are done handling this state, set node to a TSA state */
+ node_p->state = NES_CM_STATE_TSA;
+ create_event(node_p, NES_CM_EVENT_CONNECTED);
+ break;
+
+ case NES_CM_STATE_ESTABLISHED:
+ /* we are expecting an MPA req frame */
+ ret = parse_mpa(node_p, dataloc, datasize);
+ if (ret < 0)
+ break;
+ dprintk("%s[%u] -- MPA frame size = %u\n", __FILE__, __LINE__, ret);
+ node_p->state = NES_CM_STATE_TSA;
+ /* we got a valid MPA request, create an event */
+ create_event(node_p, NES_CM_EVENT_MPA_REQ);
+ break;
+ case NES_CM_STATE_TSA:
+ handle_exception_pkt(node_p, skb_p);
+ break;
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ default:
+ ret = -1;
+ }
+ }
+
+ dprintk("%s[%u] Exit\n", __FUNCTION__, __LINE__);
+ return(ret);
+}
+
+
+/**
+ * mini_cm_listen - create a listen node with params
+ */
+static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *core_p,
+ struct nes_vnic *nesvnic, struct nes_cm_info *nfo_p)
+{
+ struct nes_cm_listener *listen_p;
+ unsigned long flags;
+
+ /* create a CM listen node (1/2 node to compare incoming traffic to) */
+ listen_p = (struct nes_cm_listener *)kzalloc(sizeof(*listen_p), GFP_ATOMIC);
+ if (!listen_p)
+ return NULL;
+
+ memset(listen_p, 0, sizeof(struct nes_cm_listener));
+ listen_p->loc_addr = htonl(nfo_p->loc_addr);
+ listen_p->loc_port = htons(nfo_p->loc_port);
+ listen_p->cm_id = nfo_p->cm_id;
+ atomic_set(&listen_p->ref_count, 1);
+ listen_p->core_p = core_p;
+ atomic_inc(&core_p->node_cnt);
+ atomic_inc(&core_p->session_id);
+
+ listen_p->session_id = (u32)(atomic_read(&core_p->session_id) + current->tgid);
+ listen_p->conn_type = nfo_p->conn_type;
+
+ spin_lock_irqsave(&core_p->listen_list_lock, flags);
+ list_add(&listen_p->list, &core_p->listen_list.list);
+ spin_unlock_irqrestore(&core_p->listen_list_lock, flags);
+ atomic_inc(&core_p->listen_node_cnt);
+
+ dprintk("%s[%u] -- Api - listen(): addr=0x%08X, port=0x%04x\n",
+ __FILE__,__LINE__, ntohs(nfo_p->loc_addr), ntohs(nfo_p->loc_port));
+
+ return(listen_p);
+}
+
+
+/**
+ * mini_cm_connect - make a connection node with params
+ */
+struct nes_cm_node * mini_cm_connect(struct nes_cm_core *core_p,
+ struct nes_vnic *nesvnic, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_info *nfo_p)
+{
+ int ret = 0;
+ struct nes_cm_node *node_p;
+
+ u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+ ntohs(mpa_frame_p->priv_data_len);
+
+ nfo_p->loc_addr = htonl(nfo_p->loc_addr);
+ nfo_p->rem_addr = htonl(nfo_p->rem_addr);
+ nfo_p->loc_port = htons(nfo_p->loc_port);
+ nfo_p->rem_port = htons(nfo_p->rem_port);
+
+ /* create a CM connection node */
+ node_p = make_cm_node(core_p, nesvnic, nfo_p, NULL);
+ if (!node_p)
+ return(NULL);
+
+
+ /* set our node side to client (active) side */
+ node_p->tcp_cntxt.client = 1;
+ /* init our MPA frame ptr */
+ nes_dump_mem(mpa_frame_p, mpa_frame_size);
+ memcpy(&node_p->mpa_frame_p, mpa_frame_p, mpa_frame_size);
+ node_p->mpa_frame_size = mpa_frame_size;
+
+ /* send a syn and goto syn sent state */
+ node_p->state = NES_CM_STATE_SYN_SENT;
+ ret = send_syn(node_p, 0);
+
+ dprintk("%s[%u] -- Exit\n", __FUNCTION__,__LINE__);
+
+ return(node_p);
+}
+
+
+/**
+ * mini_cm_accept - accept a connection
+ * This function is never called
+ */
+int mini_cm_accept(struct nes_cm_core *core_p, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_node *node_p)
+{
+ return(0);
+}
+
+
+/**
+ * mini_cm_reject - reject and teardown a connection
+ */
+int mini_cm_reject(struct nes_cm_core *core_p, struct ietf_mpa_frame *mpa_frame_p,
+ struct nes_cm_node *node_p)
+{
+ int ret = 0;
+ struct sk_buff *skb_p;
+ u16 mpa_frame_size = sizeof(struct ietf_mpa_frame) +
+ ntohs(mpa_frame_p->priv_data_len);
+
+ skb_p = get_free_pkt(node_p);
+ if (!skb_p) {
+ dprintk("%s:%s[%u] -- Failed to get a Free pkt\n",__FILE__, __FUNCTION__, __LINE__);
+ return (-1);
+ }
+
+ /* send an MPA Request frame */
+ form_cm_frame(skb_p, node_p, NULL, 0, mpa_frame_p, mpa_frame_size, SET_ACK | SET_FIN);
+ ret = schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_SEND, 1);
+
+ node_p->state = NES_CM_STATE_CLOSED;
+ ret = send_fin(node_p, NULL);
+
+ if (ret < 0) {
+ printk(KERN_INFO PFX "failed to send MPA Reply (reject)\n");
+ return (ret);
+ }
+
+ dprintk("%s[%u] -- \n", __FILE__, __LINE__);
+ return(ret);
+}
+
+
+/**
+ * mini_cm_close
+ */
+int mini_cm_close(struct nes_cm_core *core_p, struct nes_cm_node *node_p)
+{
+ int ret = 0;
+
+ if (!core_p || !node_p)
+ return(-EINVAL);
+
+ switch (node_p->state) {
+ /* if passed in node is null, create a reference key node for node search */
+ /* check if we found an owner node for this pkt */
+ case NES_CM_STATE_LISTENING:
+ ret = destroy_cm_node(core_p, node_p);
+ break;
+ case NES_CM_STATE_SYN_RCVD:
+ case NES_CM_STATE_SYN_SENT:
+ case NES_CM_STATE_ONE_SIDE_ESTABLISHED:
+ case NES_CM_STATE_ESTABLISHED:
+ case NES_CM_STATE_ACCEPTING:
+ case NES_CM_STATE_MPAREQ_SENT:
+ node_p->state = NES_CM_STATE_FIN_WAIT1;
+ send_fin(node_p, NULL);
+ break;
+ case NES_CM_STATE_CLOSE_WAIT:
+ node_p->state = NES_CM_STATE_LAST_ACK;
+ send_fin(node_p, NULL);
+ break;
+ case NES_CM_STATE_FIN_WAIT1:
+ case NES_CM_STATE_FIN_WAIT2:
+ case NES_CM_STATE_LAST_ACK:
+ case NES_CM_STATE_TIME_WAIT:
+ case NES_CM_STATE_CLOSING:
+ ret = -1;
+ break;
+ case NES_CM_STATE_UNKNOWN:
+ case NES_CM_STATE_INITED:
+ case NES_CM_STATE_CLOSED:
+ case NES_CM_STATE_TSA:
+ destroy_cm_node(core_p, node_p);
+ break;
+ }
+
+ return(ret);
+}
+
+
+/**
+ * recv_pkt - recv an ETHERNET packet, and process it through CM
+ * node state machine
+ */
+int mini_cm_recv_pkt(struct nes_cm_core *core_p, struct nes_vnic *nesvnic,
+ struct sk_buff *skb_p)
+{
+ struct nes_cm_node *node_p = NULL;
+ struct nes_cm_listener *listener = NULL;
+ struct iphdr *iphdr_p;
+ struct tcphdr *tcphdr_p;
+ struct nes_cm_info nfo;
+
+ if (!skb_p || skb_p->len < sizeof(struct iphdr) + sizeof(struct tcphdr))
+ return(-EINVAL);
+
+ iphdr_p = skb_p->nh.iph = (struct iphdr *)skb_p->data;
+ skb_p->len = htons(iphdr_p->tot_len);
+
+ tcphdr_p = skb_p->h.th = (struct tcphdr *)(skb_p->data + sizeof(struct iphdr));
+
+ nfo.loc_addr = ntohl(iphdr_p->daddr);
+ nfo.loc_port = ntohs(tcphdr_p->dest);
+ nfo.rem_addr = ntohl(iphdr_p->saddr);
+ nfo.rem_port = ntohs(tcphdr_p->source);
+
+ /* find a node this packet belongs to */
+ node_p = find_node(core_p,
+ nfo.rem_port, nfo.rem_addr,
+ nfo.loc_port, nfo.loc_addr);
+
+ if (!node_p) {
+ listener = find_listener(core_p, nfo.loc_addr, nfo.loc_port);
+ if (listener) {
+ nfo.cm_id = listener->cm_id;
+ nfo.conn_type = listener->conn_type;
+ }
+ else {
+ nfo.cm_id = NULL;
+ nfo.conn_type = 0;
+ }
+
+ node_p = make_cm_node(core_p, nesvnic, &nfo, listener);
+ if(!node_p) {
+ printk(KERN_ERR PFX "Unable to allocate node\n");
+ return (-1);
+ }
+ if (!listener) {
+ printk(KERN_ERR PFX "Packet found for unknown port %x\n", nfo.loc_port);
+ send_reset(node_p);
+ return (-1);
+ }
+ node_p->state = NES_CM_STATE_LISTENING;
+ }
+
+ schedule_nes_timer(node_p, skb_p, NES_TIMER_TYPE_RECV, 0);
+
+ return(0);
+}
+
+
+/**
+ * nes_cm_alloc_core - allocate a top level instance of a cm core
+ */
+struct nes_cm_core *nes_cm_alloc_core(void)
+{
+ int i;
+
+ struct nes_cm_core *core_p;
+ struct sk_buff *skb_p = NULL;
+
+ dprintk("%s[%u] -- Init CM Core: " __DATE__ ":" __TIME__ "\n",
+ __FILE__, __LINE__);
+
+ /* setup the CM core */
+ /* alloc top level core control structure */
+ core_p = kzalloc(sizeof(*core_p), GFP_KERNEL);
+ if (!core_p)
+ return(NULL);
+
+ INIT_LIST_HEAD(&core_p->connected_nodes);
+ init_timer(&core_p->tcp_timer);
+ core_p->tcp_timer.function = nes_cm_timer_tick;
+
+ core_p->mtu = NES_CM_DEFAULT_MTU;
+ core_p->state = NES_CM_STATE_INITED;
+ core_p->free_tx_pkt_max = NES_CM_DEFAULT_FREE_PKTS;
+
+ atomic_set(&core_p->session_id, 0);
+ atomic_set(&core_p->events_posted, 0);
+
+ /* init the packet lists */
+ skb_queue_head_init(&core_p->tx_free_list);
+
+ for (i=0; i < NES_CM_DEFAULT_FRAME_CNT; i++) {
+ skb_p = dev_alloc_skb(core_p->mtu);
+ if (!skb_p) {
+ kfree(core_p);
+ return(NULL);
+ }
+ /* add 'raw' skb to free frame list */
+ skb_queue_head(&core_p->tx_free_list, skb_p);
+ }
+
+ core_p->api = &nes_cm_api;
+
+ spin_lock_init(&core_p->ht_lock);
+ spin_lock_init(&core_p->listen_list_lock);
+
+ INIT_LIST_HEAD(&core_p->listen_list.list);
+
+ dprintk("%s[%u] -- Init CM Core completed -- core_p=%p\n",
+ __FILE__,__LINE__, core_p);
+
+ dprintk("%s[%u] Enable QUEUE EVENTS\n", __FUNCTION__, __LINE__);
+ core_p->event_wq = create_singlethread_workqueue("nesewq");
+ core_p->post_event = nes_cm_post_event;
+ dprintk("%s[%u] Enable QUEUE DISCONNECTS\n", __FUNCTION__, __LINE__);
+ core_p->disconn_wq = create_singlethread_workqueue("nesdwq");
+
+ print_core(core_p);
+ return(core_p);
+}
+
+
+/**
+ * mini_cm_dealloc_core - deallocate a top level instance of a cm core
+ */
+int mini_cm_dealloc_core(struct nes_cm_core *core_p)
+{
+ /* int i; */
+ struct list_head *list_p, *list_p_temp;
+ struct nes_cm_node *node_p;
+ struct nes_cm_listener *listen_p;
+
+ dprintk("%s[%u] -- De-Alloc CM Core (%p)\n", __FILE__, __LINE__, core_p);
+
+ if (!core_p)
+ return(-EINVAL);
+
+ barrier();
+
+ if(timer_pending(&core_p->tcp_timer)) {
+ del_timer(&core_p->tcp_timer);
+ }
+
+ destroy_workqueue(core_p->event_wq);
+ destroy_workqueue(core_p->disconn_wq);
+
+ /* walk the entire HT and free each node */
+ list_for_each_safe(list_p, list_p_temp, &core_p->connected_nodes) {
+ node_p = container_of(list_p, struct nes_cm_node, list);
+ destroy_cm_node(core_p, node_p);
+ }
+
+ list_for_each_safe(list_p, list_p_temp, &core_p->listen_list.list)
+ {
+ listen_p = container_of(list_p, struct nes_cm_listener, list);
+ mini_cm_del_listen(core_p, listen_p);
+ }
+
+ dprintk("%s[%u] -- \n", __FILE__, __LINE__);
+ kfree(core_p);
+
+ return(0);
+}
+
+
+/**
+ * mini_cm_get
+ */
+int mini_cm_get(struct nes_cm_core *core_p)
+{
+ return(core_p->state);
+}
+
+
+/**
+ * mini_cm_set
+ */
+int mini_cm_set(struct nes_cm_core *core_p, u32 type, u32 value)
+{
+ int ret = 0;
+
+ switch (type) {
+ case NES_CM_SET_PKT_SIZE:
+ core_p->mtu = value;
+ break;
+ case NES_CM_SET_FREE_PKT_Q_SIZE:
+ core_p->free_tx_pkt_max = value;
+ break;
+ default:
+ /* unknown set option */
+ ret = -EINVAL;
+ }
+
+ return(ret);
+}
+
+
+/**
+ * nes_cm_init_tsa_conn setup HW; MPA frames must be
+ * successfully exchanged when this is called
+ */
+static int nes_cm_init_tsa_conn(struct nes_qp *nesqp, struct nes_cm_node *node_p)
+{
+ int ret = 0;
+
+ if (!nesqp)
+ return(-EINVAL);
+
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_IPV4 |
+ NES_QPCONTEXT_MISC_NO_NAGLE | NES_QPCONTEXT_MISC_DO_NOT_FRAG |
+ NES_QPCONTEXT_MISC_DROS;
+
+ if(node_p->tcp_cntxt.snd_wscale)
+ nesqp->nesqp_context->misc |= NES_QPCONTEXT_MISC_WSCALE;
+
+ nesqp->nesqp_context->misc2 |= (0 << NES_QPCONTEXT_MISC2_TOS_SHIFT);
+ nesqp->nesqp_context->misc2 |= (64 << NES_QPCONTEXT_MISC2_TTL_SHIFT);
+
+ nesqp->nesqp_context->mss |= ((u32)node_p->tcp_cntxt.mss) << 16;
+
+ nesqp->nesqp_context->tcp_state_flow_label |=
+ (u32)NES_QPCONTEXT_TCPSTATE_EST << NES_QPCONTEXT_TCPFLOW_TCP_STATE_SHIFT;
+
+ nesqp->nesqp_context->pd_index_wscale |=
+ (node_p->tcp_cntxt.snd_wscale << NES_QPCONTEXT_PDWSCALE_SND_WSCALE_SHIFT) &
+ NES_QPCONTEXT_PDWSCALE_SND_WSCALE_MASK;
+
+ nesqp->nesqp_context->pd_index_wscale |=
+ (node_p->tcp_cntxt.rcv_wscale << NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_SHIFT) &
+ NES_QPCONTEXT_PDWSCALE_RCV_WSCALE_MASK;
+
+ nesqp->nesqp_context->keepalive = 0x80;
+ nesqp->nesqp_context->ts_recent = 0;
+ nesqp->nesqp_context->ts_age = 0;
+ nesqp->nesqp_context->snd_nxt = node_p->tcp_cntxt.loc_seq_num;
+ nesqp->nesqp_context->snd_wnd = node_p->tcp_cntxt.snd_wnd;
+ nesqp->nesqp_context->rcv_nxt = node_p->tcp_cntxt.rcv_nxt;
+ nesqp->nesqp_context->rcv_wnd = node_p->tcp_cntxt.rcv_wnd << node_p->tcp_cntxt.rcv_wscale;
+ nesqp->nesqp_context->snd_max = node_p->tcp_cntxt.loc_seq_num;
+ nesqp->nesqp_context->snd_una = node_p->tcp_cntxt.loc_seq_num;
+ nesqp->nesqp_context->srtt = 0;
+ nesqp->nesqp_context->rttvar = 0x4B0;
+ nesqp->nesqp_context->ssthresh = 0x3FFFC000;
+ nesqp->nesqp_context->cwnd = NES_CM_DEFAULT_RCV_WND;
+ nesqp->nesqp_context->snd_wl1 = node_p->tcp_cntxt.rcv_nxt;
+ nesqp->nesqp_context->snd_wl2 = node_p->tcp_cntxt.loc_seq_num;
+ nesqp->nesqp_context->max_snd_wnd = node_p->tcp_cntxt.max_snd_wnd;
+
+ dprintk("%s: QP%u: rcv_nxt = 0x%08X, snd_nxt = 0x%08X, Setting MSS to %u, PDWscale = 0x%08X, rcv_wnd = %u, context misc = 0x%08X.\n",__FUNCTION__,
+ nesqp->hwqp.qp_id, nesqp->nesqp_context->rcv_nxt, nesqp->nesqp_context->snd_nxt,
+ node_p->tcp_cntxt.mss, nesqp->nesqp_context->pd_index_wscale, nesqp->nesqp_context->rcv_wnd,
+ nesqp->nesqp_context->misc);
+ dprintk(" snd_wnd = 0x%08X.\n", nesqp->nesqp_context->snd_wnd);
+ dprintk(" snd_cwnd = 0x%08X.\n", nesqp->nesqp_context->cwnd);
+ dprintk(" max_swnd = 0x%08X.\n", nesqp->nesqp_context->max_snd_wnd);
+
+ dprintk("%s:%s[%u] -- Change node_p state to TSA\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ node_p->state = NES_CM_STATE_TSA;
+
+ return(ret);
+}
+
+
+/**
+ * nes_cm_disconn
+ */
+int nes_cm_disconn(struct nes_qp *nesqp)
+{
+ unsigned long flags;
+
+ dprintk("%s[%u] -- \n", __FILE__, __LINE__);
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ if (0==nesqp->disconn_pending) {
+ nesqp->disconn_pending++;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ /* nes_add_ref(&nesqp->ibqp); */
+ /* init our disconnect work element, to */
+ NES_INIT_WORK(&nesqp->disconn_work, nes_disconnect_worker, (void *)nesqp);
+
+ queue_work(g_cm_core_p->disconn_wq, &nesqp->disconn_work);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ dprintk("%s[%u] -- \n", __FILE__, __LINE__);
+ return(0);
+}
+
+
+/**
+ * nes_disconnect_worker
+ */
+void nes_disconnect_worker(void *parm)
+{
+ struct work_struct *work = parm;
+ struct nes_qp *nesqp = container_of(work, struct nes_qp, disconn_work);
+ dprintk("%s: processing AEQE id 0x%04X for QP%u.\n",
+ __FUNCTION__, nesqp->last_aeq, nesqp->hwqp.qp_id);
+ nes_cm_disconn_true(nesqp);
+}
+
+
+/**
+ * nes_cm_disconn_true
+ */
+int nes_cm_disconn_true(struct nes_qp *nesqp)
+{
+ unsigned long flags;
+ int ret = 0;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ struct nes_vnic *nesvnic;
+ u16 last_ae;
+ u8 original_hw_tcp_state;
+ u8 original_ibqp_state;
+ u8 issued_disconnect_reset = 0;
+
+ if (!nesqp) {
+ dprintk("%s[%u] -- disconnect_worker nesqp is NULL\n", __FILE__,__LINE__);
+ nes_rem_ref(&nesqp->ibqp);
+ return -1;
+ }
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ cm_id = nesqp->cm_id;
+ /* make sure we havent already closed this connection */
+ if (!cm_id) {
+ dprintk("%s[%u] -- QP%u disconnect_worker cmid is NULL\n",
+ __FILE__,__LINE__, nesqp->hwqp.qp_id);
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_rem_ref(&nesqp->ibqp);
+ return -1;
+ }
+
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ dprintk("%s:%u: Disconnecting QP%u\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id);
+
+ original_hw_tcp_state = nesqp->hw_tcp_state;
+ original_ibqp_state = nesqp->ibqp_state;
+ last_ae = nesqp->last_aeq;
+
+ dprintk("%s:%u:QP%u: Last AEQ id = 0x%04X, cm_id = %p, tcp state = %d,"
+ " ib qp state = %d, refcount = %u\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, last_ae, cm_id,
+ original_hw_tcp_state, original_ibqp_state, atomic_read(&nesqp->refcount));
+
+
+ dprintk("%s[%u] -- set ibqp_state=%u\n",
+ __FUNCTION__, __LINE__, nesqp->ibqp_state);
+
+ if ((nesqp->cm_id) && (cm_id->event_handler)) {
+ if ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ ((original_ibqp_state == IB_QPS_RTS) &&
+ (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
+ atomic_inc(&cm_disconnects);
+ cm_event.event = IW_CM_EVENT_DISCONNECT;
+ if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) {
+ issued_disconnect_reset = 1;
+ cm_event.status = IW_CM_EVENT_STATUS_RESET;
+ dprintk("%s: Generating a CM Disconnect Event (status reset) for "
+ " QP%u, cm_id = %p. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id, cm_id);
+ } else {
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ }
+
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ dprintk("%s: Generating a CM Disconnect Event for "
+ " QP%u, SQ Head = %u, SQ Tail = %u. cm_id = %p, refcount = %u. \n",
+ __FUNCTION__, nesqp->hwqp.qp_id,
+ nesqp->hwqp.sq_head, nesqp->hwqp.sq_tail, cm_id,
+ atomic_read(&nesqp->refcount));
+
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ spin_lock_irqsave(&nesqp->lock, flags);
+ }
+
+ nesqp->disconn_pending = 0;
+
+ if ((0 == issued_disconnect_reset) && (nesqp->cm_id) &&
+ (((original_ibqp_state != IB_QPS_RTS) &&
+ ((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
+ (original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED))) ||
+ (last_ae == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) ||
+ (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET) ||
+ (nesqp->hw_iwarp_state == NES_AEQE_IWARP_STATE_CLOSING))) {
+ atomic_inc(&cm_closes);
+ nesqp->cm_id = NULL;
+ nesqp->in_disconnect = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ nes_disconnect(nesqp, 1, ntohs(cm_id->local_addr.sin_port));
+
+ dprintk("%s[%u] -- \n", __FUNCTION__, __LINE__);
+
+ cm_id->provider_data = nesqp;
+ /* Send up the close complete event */
+ cm_event.event = IW_CM_EVENT_CLOSE;
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ dprintk("%s[%u] -- OFA CM upcall for QP%u, IW_CM_EVENT_CLOSE cm_id = %p."
+ " QP refcount = %d. nesadapter = %p\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, cm_id,
+ atomic_read(&nesqp->refcount), nesvnic->nesdev->nesadapter);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ cm_id->rem_ref(cm_id);
+
+ spin_lock_irqsave(&nesqp->lock, flags);
+ if (0 == nesqp->flush_issued) {
+ nesqp->flush_issued = 1;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ flush_wqes(nesvnic->nesdev, nesqp, NES_CQP_FLUSH_RQ, 1);
+ } else {
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ }
+
+ /* This reference is from either ModifyQP or the AE processing,
+ there is still a race here with modifyqp */
+ nes_rem_ref(&nesqp->ibqp);
+
+ } else {
+ cm_id = nesqp->cm_id;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ /* check to see if the inbound reset beat the outbound reset */
+ if ((!cm_id) && (last_ae==NES_AEQE_AEID_RESET_SENT)) {
+ dprintk("%s[%u] QP%u: Decing refcount due to inbound reset"
+ " beating the outbound reset.\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id);
+ nes_rem_ref(&nesqp->ibqp);
+ }
+ }
+ } else {
+ nesqp->disconn_pending = 0;
+ spin_unlock_irqrestore(&nesqp->lock, flags);
+ }
+ nes_rem_ref(&nesqp->ibqp);
+ dprintk("%s[%u] Exiting. QP%u refcount = %d\n",
+ __FUNCTION__, __LINE__, nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount));
+
+ return 0;
+}
+
+
+/**
+ * nes_disconnect
+ */
+int nes_disconnect(struct nes_qp *nesqp, int abrupt, u16 local_port)
+{
+ int ret = 0;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+
+ dprintk("%s[%u] -- Enter, QP%u\n", __FUNCTION__, __LINE__, nesqp->hwqp.qp_id);
+
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ if (!nesvnic)
+ return(-EINVAL);
+
+ nesdev = nesvnic->nesdev;
+
+ dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt));
+
+ if (nesqp->active_conn) {
+
+ /* indicate this connection is NOT active */
+ nesqp->active_conn = 0;
+ } else {
+ /* Need to free the Last Streaming Mode Message */
+ if (nesqp->ietf_frame) {
+ pci_free_consistent(nesdev->pcidev,
+ nesqp->private_data_len+sizeof(struct ietf_mpa_frame),
+ nesqp->ietf_frame, nesqp->ietf_frame_pbase);
+ }
+ }
+
+ /* close the CM node down if it is still active */
+ if (nesqp->cm_node_p) {
+ dprintk("%s[%u] -- Call close API\n", __FUNCTION__, __LINE__);
+
+ g_cm_core_p->api->close(g_cm_core_p, nesqp->cm_node_p);
+ nesqp->cm_node_p = NULL;
+ }
+
+ dprintk("%s[%u] -- Exit, QP%u\n", __FUNCTION__, __LINE__, nesqp->hwqp.qp_id);
+ return(ret);
+}
+
+
+/**
+ * nes_accept
+ */
+int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ struct ib_qp *ibqp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *node_p;
+ struct nes_adapter *adapter;
+ struct ib_qp_attr attr;
+ struct iw_cm_event cm_event;
+ struct nes_hw_qp_wqe *wqe;
+ struct nes_v4_quad nes_quad;
+ int ret;
+
+ dprintk("%s:%s:%u: data len = %u\n",
+ __FILE__, __FUNCTION__, __LINE__, conn_param->private_data_len);
+
+ ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return(-EINVAL);
+
+ /* get all our handles */
+ nesqp = to_nesqp(ibqp);
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ nesdev = nesvnic->nesdev;
+ adapter = nesdev->nesadapter;
+
+ /* since this is from a listen, we were able to put node handle into cm_id */
+ node_p = (struct nes_cm_node *)cm_id->provider_data;
+
+ /* associate the node with the QP */
+ nesqp->cm_node_p = (void *)node_p;
+
+ dprintk("%s: QP%u, node_p=%p\n", __FUNCTION__, nesqp->hwqp.qp_id, node_p);
+ atomic_inc(&cm_accepts);
+
+ dprintk("%s: netdev refcnt = %u.\n",
+ __FUNCTION__, atomic_read(&nesvnic->netdev->refcnt));
+
+ /* allocate the ietf frame and space for private data */
+ nesqp->ietf_frame = pci_alloc_consistent(nesdev->pcidev,
+ sizeof(struct ietf_mpa_frame) + conn_param->private_data_len,
+ &nesqp->ietf_frame_pbase);
+
+ if (!nesqp->ietf_frame) {
+ dprintk(KERN_ERR PFX "%s: Unable to allocate memory for private data\n",
+ __FUNCTION__);
+ return(-ENOMEM);
+ }
+
+ dprintk(PFX "%s: PCI consistent memory for "
+ "private data located @ %p (pa = 0x%08llX.) size = %u.\n",
+ __FUNCTION__, nesqp->ietf_frame,
+ (unsigned long long)nesqp->ietf_frame_pbase,
+ (u32)(conn_param->private_data_len +
+ sizeof(struct ietf_mpa_frame)));
+
+ /* setup the MPA frame */
+ nesqp->private_data_len = conn_param->private_data_len;
+ memcpy(nesqp->ietf_frame->key, IEFT_MPA_KEY_REP, IETF_MPA_KEY_SIZE);
+
+ memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+ conn_param->private_data_len);
+
+ nesqp->ietf_frame->priv_data_len = cpu_to_be16(conn_param->private_data_len);
+ nesqp->ietf_frame->rev = mpa_version;
+ nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+
+ dprintk("%s: Dump of ietf_frame=\n", __FUNCTION__);
+ nes_dump_mem(nesqp->ietf_frame, sizeof(struct ietf_mpa_frame) +
+ nesqp->private_data_len);
+
+ /* setup our first outgoing iWarp send WQE (the IETF frame response) */
+ wqe = &nesqp->hwqp.sq_vbase[0];
+
+ *((struct nes_qp **)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+ *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) |=
+ NES_SW_CONTEXT_ALIGN >> 1;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] =
+ cpu_to_le32(NES_IWARP_SQ_WQE_STREAMING | NES_IWARP_SQ_WQE_WRPDU);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] =
+ cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] =
+ cpu_to_le32((u32)nesqp->ietf_frame_pbase);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] =
+ cpu_to_le32((u32)((u64)nesqp->ietf_frame_pbase >> 32));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] =
+ cpu_to_le32(conn_param->private_data_len + sizeof(struct ietf_mpa_frame));
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+ nesqp->nesqp_context->ird_ord_sizes |=
+ NES_QPCONTEXT_ORDIRD_LSMM_PRESENT | NES_QPCONTEXT_ORDIRD_WRPDU;
+ nesqp->skip_lsmm = 1;
+
+
+ /* Cache the cm_id in the qp */
+ nesqp->cm_id = cm_id;
+ node_p->cm_id = cm_id;
+
+ /* nesqp->cm_node_p = (void *)cm_id->provider_data; */
+ cm_id->provider_data = nesqp;
+ nesqp->active_conn = 0;
+
+ nes_cm_init_tsa_conn(nesqp, node_p);
+
+ nesqp->nesqp_context->tcpPorts = ntohs(cm_id->remote_addr.sin_port) << 16;
+ nesqp->nesqp_context->tcpPorts += ntohs(cm_id->local_addr.sin_port);
+ nesqp->nesqp_context->ip0 = ntohl(cm_id->remote_addr.sin_addr.s_addr);
+
+ nesqp->nesqp_context->misc2 |=
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT;
+
+ nesqp->nesqp_context->arp_index_vlan |=
+ nes_arp_table(nesdev, nesqp->nesqp_context->ip0, NULL,
+ NES_ARP_RESOLVE) << 16;
+
+ nesqp->nesqp_context->ts_val_delta =
+ jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW);
+
+ nesqp->nesqp_context->ird_index = nesqp->hwqp.qp_id;
+
+ nesqp->nesqp_context->ird_ord_sizes |=
+ ((u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT);
+ nesqp->nesqp_context->ird_ord_sizes |= (u32)conn_param->ord;
+
+ memset(&nes_quad, 0, sizeof(nes_quad));
+
+ nes_quad.DstIpAdrIndex = (u32)PCI_FUNC(nesdev->pcidev->devfn) << 27;
+ nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+ nes_quad.TcpPorts = cm_id->remote_addr.sin_port;
+ nes_quad.TcpPorts |= (u32)cm_id->local_addr.sin_port << 16;
+
+ /* Produce hash key */
+ nesqp->hte_index = nes_crc32(1, NES_HASH_CRC_INITAL_VALUE,
+ NES_HASH_CRC_FINAL_XOR, sizeof(nes_quad),
+ (u8 *)&nes_quad, ORDER, REFIN, REFOUT);
+
+ dprintk("%s: HTE Index = 0x%08X, CRC = 0x%08X\n",
+ __FUNCTION__, nesqp->hte_index,
+ nesqp->hte_index & adapter->hte_index_mask);
+
+ nesqp->hte_index &= adapter->hte_index_mask;
+ nesqp->nesqp_context->hte_index = nesqp->hte_index;
+
+ node_p->core_p->api->accelerated(node_p->core_p, node_p);
+
+ dprintk("%s: QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X,"
+ " rcv_nxt=0x%08X, snd_nxt=0x%08X, mpa + private data length=%lu.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohl(cm_id->local_addr.sin_addr.s_addr),
+ ntohs(cm_id->local_addr.sin_port),
+ nesqp->nesqp_context->rcv_nxt,
+ nesqp->nesqp_context->snd_nxt,
+ conn_param->private_data_len+sizeof(struct ietf_mpa_frame));
+
+ attr.qp_state = IB_QPS_RTS;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL );
+
+ /* notify OF layer that accept event was successfull */
+ cm_id->add_ref(cm_id);
+
+ cm_event.event = IW_CM_EVENT_ESTABLISHED;
+ cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.provider_data = (void *)nesqp;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return(0);
+}
+
+
+/**
+ * nes_reject
+ */
+int nes_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ struct nes_cm_node *node_p;
+ struct nes_cm_core *cm_core_p;
+
+ atomic_inc(&cm_rejects);
+ node_p = (struct nes_cm_node *) cm_id->provider_data;
+ cm_core_p = node_p->core_p;
+ node_p->mpa_frame_size = sizeof(struct ietf_mpa_frame) + pdata_len;
+
+ strcpy(&node_p->mpa_frame_p.key[0], IEFT_MPA_KEY_REP);
+ memcpy(&node_p->mpa_frame_p.priv_data, pdata, pdata_len);
+
+ node_p->mpa_frame_p.priv_data_len = cpu_to_be16(pdata_len);
+ node_p->mpa_frame_p.rev = mpa_version;
+ node_p->mpa_frame_p.flags = IETF_MPA_FLAGS_CRC | IETF_MPA_FLAGS_REJECT;
+
+ cm_core_p->api->reject(cm_core_p, &node_p->mpa_frame_p, node_p);
+
+ return(0);
+}
+
+
+/**
+ * nes_connect
+ * setup and launch cm connect node
+ */
+int nes_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
+{
+ struct ib_qp *ibqp;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *cm_node_p;
+ struct nes_cm_info cm_info;
+
+ dprintk("%s[%u] data len = %u, cm_id = %p, event handler = %p.\n",
+ __FILE__, __LINE__, conn_param->private_data_len,
+ cm_id, cm_id->event_handler);
+
+ if (cm_id->remote_addr.sin_addr.s_addr == cm_id->local_addr.sin_addr.s_addr) {
+ dprintk("Failing loopback connect attempt,"
+ " local address = 0x%08X:0x%04X, remote address = 0x%08X:0x%04X\n",
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohl(cm_id->local_addr.sin_addr.s_addr),
+ ntohs(cm_id->local_addr.sin_port));
+ return(-EINVAL);
+ }
+
+ ibqp = nes_get_qp(cm_id->device, conn_param->qpn);
+ if (!ibqp)
+ return(-EINVAL);
+ nesqp = to_nesqp(ibqp);
+ if (!nesqp)
+ return(-EINVAL);
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ if (!nesvnic)
+ return(-EINVAL);
+ nesdev = nesvnic->nesdev;
+ if (!nesdev)
+ return(-EINVAL);
+
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+ atomic_inc(&cm_connects);
+
+ nesqp->ietf_frame = kzalloc(sizeof(struct ietf_mpa_frame) +
+ conn_param->private_data_len, GFP_KERNEL);
+ if (!nesqp->ietf_frame)
+ return(-ENOMEM);
+
+ /* set qp as having an active connection */
+ nesqp->active_conn = 1;
+
+ dprintk("%s: QP%u, Destination IP = 0x%08X:0x%04X, local = 0x%08X:0x%04X.\n",
+ __FUNCTION__, nesqp->hwqp.qp_id,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohl(cm_id->local_addr.sin_addr.s_addr),
+ ntohs(cm_id->local_addr.sin_port));
+
+ /* cache the cm_id in the qp */
+ nesqp->cm_id = cm_id;
+
+ cm_id->provider_data = nesqp;
+
+ cm_id->add_ref(cm_id);
+
+ /* copy the private data */
+ if (conn_param->private_data_len) {
+ memcpy(nesqp->ietf_frame->priv_data, conn_param->private_data,
+ conn_param->private_data_len);
+ }
+
+ nesqp->private_data_len = conn_param->private_data_len;
+ nesqp->nesqp_context->ird_ord_sizes |= (u32)conn_param->ord;
+ dprintk("%s:requested ord = 0x%08X.\n",
+ __FUNCTION__, (u32)conn_param->ord);
+ dprintk("%s:mpa private data len =%u\n",
+ __FUNCTION__, conn_param->private_data_len);
+
+ strcpy(&nesqp->ietf_frame->key[0], IEFT_MPA_KEY_REQ);
+ nesqp->ietf_frame->flags = IETF_MPA_FLAGS_CRC;
+ nesqp->ietf_frame->rev = IETF_MPA_VERSION;
+ nesqp->ietf_frame->priv_data_len = htons(conn_param->private_data_len);
+
+ dprintk("%s:[%u] priv_data_len = %u\n", __FILE__, __LINE__,
+ ntohs(nesqp->ietf_frame->priv_data_len));
+
+ dprintk("%s:%s[%u] set bit in APBVT\n", __FILE__, __FUNCTION__, __LINE__);
+
+ nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+ PCI_FUNC(nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+
+ /* set up the connection params for the node */
+ cm_info.loc_addr = (cm_id->local_addr.sin_addr.s_addr);
+ cm_info.loc_port = (cm_id->local_addr.sin_port);
+ cm_info.rem_addr = (cm_id->remote_addr.sin_addr.s_addr);
+ cm_info.rem_port = (cm_id->remote_addr.sin_port);
+ cm_info.cm_id = cm_id;
+ cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+ /* create a connect CM node connection */
+ cm_node_p = g_cm_core_p->api->connect(g_cm_core_p, nesvnic, nesqp->ietf_frame, &cm_info);
+ nesqp->cm_node_p = cm_node_p;
+
+ if (!cm_node_p)
+ return(-ENOMEM);
+
+ return(0);
+}
+
+
+/**
+ * nes_create_listen
+ */
+int nes_create_listen(struct iw_cm_id *cm_id, int backlog)
+{
+ struct nes_vnic *nesvnic;
+ struct nes_cm_listener *cm_node_p;
+ struct nes_cm_info cm_info;
+ struct nes_adapter *adapter;
+
+ struct rdma_cm_id* rdma_cm_id = cm_id->context;
+ BUG_ON(!rdma_cm_id);
+
+ dprintk("%s[%u] Enter\n", __FUNCTION__, __LINE__);
+
+ nesvnic = to_nesvnic(cm_id->device);
+ if (!nesvnic)
+ return(-EINVAL);
+ adapter = nesvnic->nesdev->nesadapter;
+
+ /* setup listen params in our api call struct */
+ cm_info.loc_addr = cm_id->local_addr.sin_addr.s_addr;
+ cm_info.loc_port = cm_id->local_addr.sin_port;
+ /* cm_info.value = backlog; */
+ cm_info.cm_id = cm_id;
+
+ cm_info.conn_type = NES_CM_IWARP_CONN_TYPE;
+
+ cm_node_p = g_cm_core_p->api->listen(g_cm_core_p, nesvnic, &cm_info);
+
+ cm_id->provider_data = cm_node_p;
+ if (!cm_node_p) {
+ dprintk("%s[%u] Error returned from listen API call\n",
+ __FUNCTION__, __LINE__);
+ return(-ENOMEM);
+ }
+
+ cm_id->add_ref(cm_id);
+
+ cm_id->provider_data = (void *)cm_node_p;
+
+ nes_manage_apbvt(nesvnic, ntohs(cm_id->local_addr.sin_port),
+ PCI_FUNC(nesvnic->nesdev->pcidev->devfn), NES_MANAGE_APBVT_ADD);
+
+ dprintk("%s[%u] Exiting create listen, netdev->refcnt = %u.\n",
+ __FUNCTION__, __LINE__, atomic_read(&nesvnic->netdev->refcnt));
+ return(0);
+}
+
+
+/**
+ * nes_destroy_listen
+ */
+int nes_destroy_listen(struct iw_cm_id *cm_id)
+{
+ dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+ if (cm_id->provider_data)
+ g_cm_core_p->api->stop_listener(g_cm_core_p, cm_id->provider_data);
+ else
+ dprintk("cm_id->provider_data was NULL\n");
+ cm_id->rem_ref(cm_id);
+
+ return(0);
+}
+
+
+/**
+ * nes_cm_recv
+ */
+int nes_cm_recv(struct sk_buff *skb_p, struct net_device *netdevice)
+{
+ g_cm_core_p->api->recv_pkt(g_cm_core_p, netdev_priv(netdevice), skb_p);
+ return(0);
+}
+
+
+/**
+ * nes_cm_start
+ * Start and init a cm core module
+ */
+int nes_cm_start(void)
+{
+ dprintk("%s:%s[%u]\n", __FILE__, __FUNCTION__, __LINE__);
+ /* create the primary CM core, pass this handle to subsequent core inits */
+ g_cm_core_p = nes_cm_alloc_core();
+
+ return (0);
+}
+
+
+/**
+ * nes_cm_stop
+ * stop and dealloc all cm core instances
+ */
+int nes_cm_stop(void)
+{
+ g_cm_core_p->api->destroy_cm_core(g_cm_core_p);
+ return (0);
+}
+
+
+/**
+ * cm_event_connected
+ * handle a connected event, setup QPs and HW
+ */
+void cm_event_connected(struct nes_cm_event *event_p)
+{
+ int ret;
+ struct nes_qp *nesqp;
+ struct nes_vnic *nesvnic;
+ struct nes_device *nesdev;
+ struct nes_cm_node *node_p;
+ struct nes_adapter *nesadapter;
+ struct ib_qp_attr attr;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ struct nes_hw_qp_wqe *wqe;
+ struct nes_v4_quad nes_quad;
+
+ /* get all our handles */
+ node_p = event_p->node_p;
+ cm_id = node_p->cm_id;
+ dprintk("%s[%u] cm_event_connected - %p - cm_id = %p\n",
+ __FUNCTION__, __LINE__, node_p, cm_id);
+ nesqp = (struct nes_qp *)cm_id->provider_data;
+ nesvnic = to_nesvnic(nesqp->ibqp.device);
+ nesdev = nesvnic->nesdev;
+ nesadapter = nesdev->nesadapter;
+
+ atomic_inc(&cm_connecteds);
+ dprintk("%s[%u] Attempting to connect to 0x%08X:0x%04X on local port 0x%04X.\n",
+ __FUNCTION__, __LINE__,
+ ntohl(cm_id->remote_addr.sin_addr.s_addr),
+ ntohs(cm_id->remote_addr.sin_port),
+ ntohs(cm_id->local_addr.sin_port));
+
+ nes_cm_init_tsa_conn(nesqp, node_p);
+
+ /* set the QP tsa context */
+ nesqp->nesqp_context->tcpPorts = ntohs(cm_id->remote_addr.sin_port) << 16;
+ nesqp->nesqp_context->tcpPorts += ntohs(cm_id->local_addr.sin_port);
+ nesqp->nesqp_context->ip0 = ntohl(cm_id->remote_addr.sin_addr.s_addr);
+
+ nesqp->nesqp_context->misc2 |=
+ (u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_QPCONTEXT_MISC2_SRC_IP_SHIFT;
+ nesqp->nesqp_context->arp_index_vlan |=
+ nes_arp_table(nesdev, nesqp->nesqp_context->ip0,
+ NULL, NES_ARP_RESOLVE) << 16;
+ nesqp->nesqp_context->ts_val_delta =
+ jiffies - nes_read_indexed(nesdev, NES_IDX_TCP_NOW);
+ nesqp->nesqp_context->ird_index = nesqp->hwqp.qp_id;
+ nesqp->nesqp_context->ird_ord_sizes |=
+ (u32)1 << NES_QPCONTEXT_ORDIRD_IWARP_MODE_SHIFT;
+
+ /* Adjust tail for not having a LSMM */
+ nesqp->hwqp.sq_tail = 1;
+
+#if defined(NES_SEND_FIRST_WRITE)
+ if (send_first) {
+ wqe = &nesqp->hwqp.sq_vbase[0];
+ *((struct nes_qp **)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) = nesqp;
+ *((u64 *)&wqe->wqe_words[NES_IWARP_SQ_WQE_COMP_CTX_LOW_IDX]) |=
+ NES_SW_CONTEXT_ALIGN>>1;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_IWARP_SQ_OP_RDMAW);
+ wqe->wqe_words[NES_IWARP_SQ_WQE_TOTAL_PAYLOAD_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_LOW_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_FRAG0_HIGH_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_LENGTH0_IDX] = 0;
+ wqe->wqe_words[NES_IWARP_SQ_WQE_STAG0_IDX] = 0;
+
+ /* use the reserved spot on the WQ for the extra first WQE */
+ nesqp->nesqp_context->ird_ord_sizes &= ~(NES_QPCONTEXT_ORDIRD_LSMM_PRESENT |
+ NES_QPCONTEXT_ORDIRD_WRPDU | NES_QPCONTEXT_ORDIRD_ALSMM);
+ nesqp->skip_lsmm = 1;
+ nesqp->hwqp.sq_tail = 0;
+ nes_write32(nesdev->regs + NES_WQE_ALLOC,
+ (1 << 24) | 0x00800000 | nesqp->hwqp.qp_id);
+ }
+#endif
+
+ memset(&nes_quad, 0, sizeof(nes_quad));
+
+ nes_quad.DstIpAdrIndex = (u32)PCI_FUNC(nesdev->pcidev->devfn) << 27;
+ nes_quad.SrcIpadr = cm_id->remote_addr.sin_addr.s_addr;
+ nes_quad.TcpPorts = cm_id->remote_addr.sin_port;
+ nes_quad.TcpPorts |= (u32)cm_id->local_addr.sin_port << 16;
+
+ nesqp->hte_index = nes_crc32( 1, NES_HASH_CRC_INITAL_VALUE,
+ NES_HASH_CRC_FINAL_XOR, sizeof(nes_quad), (u8 *)&nes_quad,
+ ORDER, REFIN, REFOUT);
+
+ dprintk("%s: HTE Index = 0x%08X, CRC = 0x%08X\n", __FUNCTION__,
+ nesqp->hte_index, nesqp->hte_index & nesadapter->hte_index_mask);
+
+ nesqp->hte_index &= nesadapter->hte_index_mask;
+ nesqp->nesqp_context->hte_index = nesqp->hte_index;
+
+ nesqp->ietf_frame = &node_p->mpa_frame_p;
+ nesqp->private_data_len = (u8) node_p->mpa_frame_size;
+ node_p->core_p->api->accelerated(node_p->core_p, node_p);
+
+ /* modify QP state to rts */
+ attr.qp_state = IB_QPS_RTS;
+ nes_modify_qp(&nesqp->ibqp, &attr, IB_QP_STATE, NULL);
+
+ /* notify OF layer we successfully created the requested connection */
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr.sin_family = AF_INET;
+ cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
+ cm_event.remote_addr = cm_id->remote_addr;
+
+ cm_event.private_data = (void *) event_p->node_p->mpa_frame_b;
+ cm_event.private_data_len = (u8) event_p->node_p->mpa_frame_size;
+
+ cm_event.local_addr.sin_addr.s_addr = event_p->cm_info.rem_addr;
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ dprintk("%s: Exiting connect thread for QP%u\n",
+ __FUNCTION__, nesqp->hwqp.qp_id );
+
+ return;
+}
+
+
+/**
+ * cm_event_connect_error
+ */
+void cm_event_connect_error(struct nes_cm_event *event_p)
+{
+ struct nes_qp *nesqp;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ /* struct nes_cm_info cm_info; */
+ int ret;
+
+ if (!event_p->node_p)
+ return;
+
+ /* close and destroy the node */
+ event_p->node_p->core_p->api->close(event_p->node_p->core_p, event_p->node_p);
+
+ cm_id = event_p->node_p->cm_id;
+ if(!cm_id)
+ return;
+
+ dprintk("cm_event_connect_error - %p - cm_id = %p\n", event_p->node_p, cm_id);
+ nesqp = cm_id->provider_data;
+
+ if(!nesqp)
+ return;
+
+ /* notify OF layer about this connection error event */
+ /* cm_id->rem_ref(cm_id); */
+ nesqp->cm_id = NULL;
+ cm_id->provider_data = NULL;
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.status = IW_CM_EVENT_STATUS_REJECTED;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ cm_id->rem_ref(cm_id);
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return;
+}
+
+
+/**
+ * cm_event_reset
+ */
+void cm_event_reset(struct nes_cm_event *event_p)
+{
+ struct nes_qp *nesqp;
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ /* struct nes_cm_info cm_info; */
+ int ret;
+
+ if (!event_p->node_p)
+ return;
+
+ cm_id = event_p->node_p->cm_id;
+
+ dprintk("cm_event_connect_error - %p - cm_id = %p\n", event_p->node_p, cm_id);
+ nesqp = cm_id->provider_data;
+
+ /* notify OF layer about this connection error event */
+ cm_id->rem_ref(cm_id);
+ nesqp->cm_id = NULL;
+ /* cm_id->provider_data = NULL; */
+ cm_event.event = IW_CM_EVENT_DISCONNECT;
+ cm_event.status = IW_CM_EVENT_STATUS_RESET;
+ cm_event.provider_data = cm_id->provider_data;
+ cm_event.local_addr = cm_id->local_addr;
+ cm_event.remote_addr = cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ dprintk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return;
+}
+
+
+/**
+ * cm_event_mpa_req
+ */
+void cm_event_mpa_req(struct nes_cm_event *event_p)
+{
+ struct iw_cm_id *cm_id;
+ struct iw_cm_event cm_event;
+ int ret;
+ struct nes_cm_node *node_p;
+
+ node_p = event_p->node_p;
+ if (!node_p)
+ return;
+ cm_id = node_p->cm_id;
+
+ atomic_inc(&cm_connect_reqs);
+ dprintk("%s[%u] cm_event_mpa_req - %p - cm_id = %p\n",
+ __FUNCTION__, __LINE__, node_p, cm_id);
+
+ cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
+ cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.provider_data = (void *)node_p;
+
+ cm_event.local_addr.sin_family = AF_INET;
+ cm_event.local_addr.sin_port = htons(event_p->cm_info.loc_port);
+ cm_event.local_addr.sin_addr.s_addr = htonl(event_p->cm_info.loc_addr);
+
+ cm_event.remote_addr.sin_family = AF_INET;
+ cm_event.remote_addr.sin_port = htons(event_p->cm_info.rem_port);
+ cm_event.remote_addr.sin_addr.s_addr = htonl(event_p->cm_info.rem_addr);
+
+ cm_event.private_data = node_p->mpa_frame_b;
+ cm_event.private_data_len = (u8) node_p->mpa_frame_size;
+
+ ret = cm_id->event_handler(cm_id, &cm_event);
+ if (ret)
+ printk("%s[%u] OFA CM event_handler returned, ret=%d\n",
+ __FUNCTION__, __LINE__, ret);
+
+ return;
+}
+
+
+static void nes_cm_event_handler(void *parm);
+
+/**
+ * nes_cm_post_event
+ * post an event to the cm event handler
+ */
+int nes_cm_post_event(struct nes_cm_event *event_p)
+{
+ atomic_inc(&event_p->node_p->core_p->events_posted);
+
+ NES_INIT_WORK(&event_p->event_work, nes_cm_event_handler, (void *)event_p);
+ dprintk("%s[%u] queue_work, event_p=%p\n", __FUNCTION__, __LINE__, event_p);
+
+ queue_work(event_p->node_p->core_p->event_wq, &event_p->event_work);
+
+ dprintk("%s[%u] Exit\n", __FUNCTION__, __LINE__);
+ return(0);
+}
+
+
+/**
+ * nes_cm_event_handler
+ * worker function to handle cm events
+ * will free instance of nes_cm_event
+ */
+static void nes_cm_event_handler(void *parm)
+{
+ struct work_struct *work = parm;
+ struct nes_cm_event *event_p = container_of(work, struct nes_cm_event, event_work);
+ struct nes_cm_core *core_p;
+
+ dprintk("%s[%u] Enter\n", __FUNCTION__, __LINE__);
+
+ if (!event_p)
+ return;
+ core_p = event_p->node_p->core_p;
+ dprintk("%s[%u] event_p=%p, event_p->type=%u, events posted=%u\n",
+ __FUNCTION__, __LINE__,
+ event_p, event_p->type, atomic_read(&core_p->events_posted));
+
+ switch (event_p->type) {
+ case NES_CM_EVENT_MPA_REQ:
+ cm_event_mpa_req(event_p);
+ dprintk("%s:%s[%u] -- CM Event: MPA REQUEST\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ break;
+ case NES_CM_EVENT_RESET:
+ dprintk("%s:%s[%u] -- CM Event: RESET\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ cm_event_reset(event_p);
+ break;
+ case NES_CM_EVENT_CONNECTED:
+ cm_event_connected(event_p);
+ dprintk("%s:%s[%u] -- CM Event: CONNECTED\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ break;
+ case NES_CM_EVENT_ABORTED:
+ cm_event_connect_error(event_p);
+ dprintk("%s:%s[%u] -- CM Event: ABORTED\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ break;
+ case NES_CM_EVENT_DROPPED_PKT:
+ dprintk("%s:%s[%u] -- CM Event: DROPPED PKT\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ break;
+ default:
+ dprintk("%s:%s[%u] -- CM Event: UNKNOWN EVENT TYPE\n",
+ __FILE__, __FUNCTION__, __LINE__);
+ break;
+ }
+
+ dprintk("%s[%u] decrement events_posted, =%u\n",
+ __FUNCTION__, __LINE__, atomic_read(&core_p->events_posted));
+ atomic_dec(&core_p->events_posted);
+ dprintk("%s[%u] free event_p=%p\n", __FUNCTION__, __LINE__, event_p);
+
+ kfree(event_p);
+ dprintk("%s[%u] Exit\n", __FUNCTION__, __LINE__);
+
+ return;
+}
^ permalink raw reply
* Re: [patch 1/1] NetLabel: add missing rcu_dereference() calls in the LSM domain mapping hash table
From: David Miller @ 2007-08-08 0:53 UTC (permalink / raw)
To: paul.moore; +Cc: netdev
In-Reply-To: <20070807205458.599982536@hp.com>
From: "Paul Moore" <paul.moore@hp.com>
Date: Tue, 07 Aug 2007 16:54:50 -0400
> The LSM domain mapping head table pointer was not being referenced via the RCU
> safe dereferencing function, rcu_dereference(). This patch adds those missing
> calls to the NetLabel code.
>
> This has been tested using recent linux-2.6 git kernels with no visible
> regressions.
>
> Signed-off-by: Paul Moore <paul.moore@hp.com>
Patch applied, thanks Paul.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox