LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [2.6.19 PATCH 1/7] ehea: interface to network stack
From: Jan-Bernd Themann @ 2006-08-18 11:29 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, Thomas Klein,
	linux-ppc, Christoph Raisch, Marcus Eder

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com> 


 drivers/net/ehea/ehea_main.c | 2480 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 2480 insertions(+)



--- linux-2.6.18-rc4-orig/drivers/net/ehea/ehea_main.c	1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_main.c	2006-08-18 00:01:02.147117523 -0700
@@ -0,0 +1,2480 @@
+/*
+ *  linux/drivers/net/ehea/ehea_main.c
+ *
+ *  eHEA ethernet device driver for IBM eServer System p
+ *
+ *  (C) Copyright IBM Corp. 2006
+ *
+ *  Authors:
+ *       Christoph Raisch <raisch@de.ibm.com>
+ *       Jan-Bernd Themann <themann@de.ibm.com>
+ *       Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <net/ip.h>
+
+#include "ehea.h"
+#include "ehea_qmr.h"
+#include "ehea_phyp.h"
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
+MODULE_DESCRIPTION("IBM eServer HEA Driver");
+MODULE_VERSION(DRV_VERSION);
+
+
+static int msg_level = -1;
+module_param(msg_level, int, 0);
+MODULE_PARM_DESC(msg_level, "msg_level");
+
+
+static struct net_device_stats *ehea_get_stats(struct net_device *dev)
+{
+	int i;
+	u64 hret = H_HARDWARE;
+	u64 rx_packets = 0;
+	struct ehea_port *port = netdev_priv(dev);
+	struct hcp_query_ehea_port_cb_2 *cb2 = NULL;
+	struct net_device_stats *stats = &port->stats;
+
+	cb2 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb2) {
+		ehea_error("no mem for cb2");
+		goto get_stat_exit;
+	}
+
+	hret = ehea_h_query_ehea_port(port->adapter->handle,
+				      port->logical_port_id,
+				      H_PORT_CB2,
+				      H_PORT_CB2_ALL,
+				      cb2);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto get_stat_exit2;
+	}
+
+	if (netif_msg_hw(port))
+		ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
+
+	for (i = 0; i < port->num_def_qps; i++)
+		rx_packets += port->port_res[i].rx_packets;
+
+	stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp;
+	stats->multicast = cb2->rxmcp;
+	stats->rx_errors = cb2->rxuerr;
+	stats->rx_bytes = cb2->rxo;
+	stats->tx_bytes = cb2->txo;
+	stats->rx_packets = rx_packets;
+get_stat_exit2:
+        kfree(cb2);
+get_stat_exit:
+	return stats;
+}
+
+
+static inline int ehea_refill_rq1(struct ehea_port_res *pr, int index,
+				  int nr_of_wqes)
+{
+	int i;
+	int ret = 0;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+	int max_index_mask = pr->skb_arr_rq1_len - 1;
+
+	if (!nr_of_wqes)
+		return 0;
+
+	for (i = 0; i < nr_of_wqes; i++) {
+		if (!skb_arr_rq1[index]) {
+			skb_arr_rq1[index] = dev_alloc_skb(EHEA_LL_PKT_SIZE);
+
+			if (!skb_arr_rq1[index]) {
+				ehea_error("no mem for skb/%d wqes filled", i);
+				ret = -ENOMEM;
+				break;
+			}
+		}
+		index--;
+		index &= max_index_mask;
+	}
+	/* Ring doorbell */
+	ehea_update_rq1a(pr->qp, i);
+
+	return ret;
+}
+
+static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
+{
+	int i;
+	int ret = 0;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+
+	for (i = 0; i < pr->skb_arr_rq1_len; i++) {
+		skb_arr_rq1[i] = dev_alloc_skb(EHEA_LL_PKT_SIZE);
+		if (!skb_arr_rq1[i]) {
+			ehea_error("no mem for skb/%d skbs filled.", i);
+			ret = -ENOMEM;
+			goto nomem;
+		}
+	}
+	/* Ring doorbell */
+	ehea_update_rq1a(pr->qp, nr_rq1a);
+nomem:
+	return ret;
+}
+
+static inline int ehea_refill_rq2_def(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	int i;
+	int ret = 0;
+	struct ehea_qp *qp;
+	struct ehea_rwqe *rwqe;
+	struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2;
+	int index, max_index_mask;
+
+	if (!nr_of_wqes)
+		return 0;
+
+	qp = pr->qp;
+
+	index = pr->skb_rq2_index;
+	max_index_mask = pr->skb_arr_rq2_len - 1;
+	for (i = 0; i < nr_of_wqes; i++) {
+		struct sk_buff *skb = dev_alloc_skb(EHEA_RQ2_PKT_SIZE
+						    + NET_IP_ALIGN);
+		if (!skb) {
+			ehea_error("no mem for skb/%d wqes filled", i);
+			ret = -ENOMEM;
+			break;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		skb_arr_rq2[index] = skb;
+
+		rwqe = ehea_get_next_rwqe(qp, 2);
+		rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_RWQE2_TYPE)
+		            | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+		rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
+		rwqe->sg_list[0].vaddr = (u64)skb->data;
+		rwqe->sg_list[0].len = EHEA_RQ2_PKT_SIZE;
+		rwqe->data_segments = 1;
+
+		index++;
+		index &= max_index_mask;
+	}
+	pr->skb_rq2_index = index;
+
+	/* Ring doorbell */
+	iosync();
+	ehea_update_rq2a(qp, i);
+	return ret;
+}
+
+
+static inline int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	return ehea_refill_rq2_def(pr, nr_of_wqes);
+}
+
+static inline int ehea_refill_rq3_def(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	int i;
+	int ret = 0;
+	struct ehea_qp *qp = pr->qp;
+	struct ehea_rwqe *rwqe;
+	int skb_arr_rq3_len = pr->skb_arr_rq3_len;
+	struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3;
+	int index, max_index_mask;
+
+	if (nr_of_wqes == 0)
+		return -EINVAL;
+        
+	index = pr->skb_rq3_index;
+	max_index_mask = skb_arr_rq3_len - 1;
+	for (i = 0; i < nr_of_wqes; i++) {
+		struct sk_buff *skb = dev_alloc_skb(EHEA_MAX_PACKET_SIZE
+						    + NET_IP_ALIGN);
+		if (!skb) {
+			ehea_error("no mem for skb/%d wqes filled", i);
+			ret = -ENOMEM;
+			break;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		rwqe = ehea_get_next_rwqe(qp, 3);
+
+		skb_arr_rq3[index] = skb;
+
+		rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_RWQE3_TYPE)
+			    | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+		rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
+		rwqe->sg_list[0].vaddr = (u64)skb->data;
+		rwqe->sg_list[0].len = EHEA_MAX_PACKET_SIZE;
+		rwqe->data_segments = 1;
+
+		index++;
+		index &= max_index_mask;
+	}
+	pr->skb_rq3_index = index;
+
+	/* Ring doorbell */
+	iosync();
+	ehea_update_rq3a(qp, i);
+	return ret;
+}
+
+
+static inline int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
+{
+	return ehea_refill_rq3_def(pr, nr_of_wqes);
+}
+
+static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
+{
+	*rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5;
+	if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0)
+		return 0;
+	if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0)
+	    && (cqe->header_length == 0))
+		return 0;
+	return -EINVAL;
+}
+
+static inline void ehea_fill_skb(struct net_device *dev,
+				 struct sk_buff *skb, struct ehea_cqe *cqe)
+{
+	int length = cqe->num_bytes_transfered - 4;	/*remove CRC */
+	skb_put(skb, length);
+	skb->dev = dev;
+	skb->ip_summed = CHECKSUM_UNNECESSARY;
+	skb->protocol = eth_type_trans(skb, dev);
+}
+
+
+
+static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
+					       int arr_len,
+					       struct ehea_cqe *cqe)
+{
+	struct sk_buff *skb;
+	void *pref;
+	int x;
+	int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+
+	x = skb_index + 1;
+	x &= (arr_len - 1);
+
+	pref = (void*)skb_array[x];
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	pref = (void*)(skb_array[x]->data);
+	prefetch(pref);
+	prefetch(pref + EHEA_CACHE_LINE);
+	prefetch(pref + EHEA_CACHE_LINE * 2);
+	prefetch(pref + EHEA_CACHE_LINE * 3);
+	skb = skb_array[skb_index];
+	skb_array[skb_index] = NULL;
+	return skb;
+}
+
+static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
+						  int arr_len, int wqe_index)
+{
+	struct sk_buff *skb;
+	void *pref;
+	int x;
+
+	x = wqe_index + 1;
+	x &= (arr_len - 1);
+
+	pref = (void*)skb_array[x];
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	pref = (void*)(skb_array[x]->data);
+	prefetchw(pref);
+	prefetchw(pref + EHEA_CACHE_LINE);
+
+	skb = skb_array[wqe_index];
+	skb_array[wqe_index] = NULL;
+	return skb;
+}
+
+static int ehea_poll(struct net_device *dev, int *budget)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr = &port->port_res[0];
+	struct ehea_cqe *cqe;
+	struct ehea_qp *qp = pr->qp;
+	int wqe_index, last_wqe_index = 0;
+	int processed = 0;
+	int processed_RQ1 = 0;
+	int processed_RQ2 = 0;
+	int processed_RQ3 = 0;
+	int rq, intreq;
+	struct sk_buff **skb_arr_rq1 = pr->skb_arr_rq1;
+	struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2;
+	struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3;
+	int skb_arr_rq1_len = pr->skb_arr_rq1_len;
+	int my_quota = min(*budget, dev->quota);
+	struct sk_buff *skb;
+	my_quota = min(my_quota, EHEA_MAX_RWQE);
+
+	/* rq0 is low latency RQ */
+	cqe = ehea_poll_rq1(qp, &wqe_index);
+	while ((my_quota > 0) && cqe) {
+		ehea_inc_rq1(qp);
+		processed_RQ1++;
+		processed++;
+		my_quota--;
+		if (netif_msg_rx_status(port))
+			ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+		last_wqe_index = wqe_index;
+		rmb();
+		if (!ehea_check_cqe(cqe, &rq)) {
+			if (rq == 1) {	/* LL RQ1 */
+				skb = get_skb_by_index_ll(skb_arr_rq1,
+							  skb_arr_rq1_len,
+							  wqe_index);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("LL rq1: skb=NULL");
+					break;
+				}
+				memcpy(skb->data, ((char*)cqe) + 64,
+				       cqe->num_bytes_transfered - 4);
+				ehea_fill_skb(dev, skb, cqe);
+			} else if (rq == 2) {  /* RQ2 */
+				skb = get_skb_by_index(skb_arr_rq2,
+						     pr->skb_arr_rq2_len, cqe);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("rq2: skb=NULL");
+					break;
+				}
+				ehea_fill_skb(dev, skb, cqe);
+				processed_RQ2++;
+			} else {  /* RQ3 */
+				skb = get_skb_by_index(skb_arr_rq3,
+						     pr->skb_arr_rq3_len, cqe);
+				if (unlikely(!skb)) {
+					if (netif_msg_rx_err(port))
+						ehea_error("rq3: skb=NULL");
+					break;
+				}
+				ehea_fill_skb(dev, skb, cqe);
+				processed_RQ3++;
+			}
+
+			if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+				vlan_hwaccel_receive_skb(skb, port->vgrp,
+							 cqe->vlan_tag);
+			else
+				netif_receive_skb(skb);
+
+		} else { /* Error occured */
+			if (netif_msg_rx_err(port))
+				ehea_dump(cqe, sizeof(*cqe), "CQE");
+			if (rq == 2) {
+				processed_RQ2++;
+				skb = get_skb_by_index(skb_arr_rq2,
+						       pr->skb_arr_rq2_len,
+						       cqe);
+				dev_kfree_skb(skb);
+			}
+			if (rq == 3) {
+				processed_RQ3++;
+				skb = get_skb_by_index(skb_arr_rq3,
+						       pr->skb_arr_rq3_len,
+						       cqe);
+				dev_kfree_skb(skb);
+			}
+		}
+		cqe = ehea_poll_rq1(qp, &wqe_index);
+	}
+
+	dev->quota -= processed;
+	*budget -= processed;
+
+	pr->p_state.ehea_poll += 1;
+	pr->rx_packets += processed;
+
+	ehea_refill_rq1(pr, last_wqe_index, processed_RQ1);
+	ehea_refill_rq2(pr, processed_RQ2);
+	ehea_refill_rq3(pr, processed_RQ3);
+	intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
+
+	if (!cqe || intreq) {
+		netif_rx_complete(dev);
+		ehea_reset_cq_ep(pr->recv_cq);
+		ehea_reset_cq_n1(pr->recv_cq);
+		cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
+		if (!cqe || intreq)
+			return 0;
+		if (!netif_rx_reschedule(dev, my_quota))
+			return 0;
+	}
+	return 1;
+}
+
+void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+{
+	struct sk_buff *skb;
+	int index, max_index_mask;
+	int i;
+
+	index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+	max_index_mask = pr->skb_arr_sq_len - 1;
+	for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
+		skb = pr->skb_arr_sq[index];
+		if (likely(skb)) {
+			dev_kfree_skb(skb);
+			pr->skb_arr_sq[index] = NULL;
+		} else {
+			ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d\n",
+				   cqe->wr_id, i, index);
+		}
+
+		index--;
+		index &= max_index_mask;
+	}
+}
+
+#define MAX_SENDCOMP_QUOTA 400
+void ehea_send_irq_tasklet(unsigned long data)
+{
+	int quota = MAX_SENDCOMP_QUOTA;
+	int cqe_counter = 0;
+	int swqe_av = 0;
+	unsigned long flags;
+	struct ehea_cqe *cqe;
+	struct ehea_port_res *pr = (struct ehea_port_res*)data;
+	struct ehea_cq *send_cq = pr->send_cq;
+	struct net_device *dev = pr->port->netdev;
+
+	do {
+		cqe = ehea_poll_cq(send_cq);
+		if (!cqe) {
+			ehea_reset_cq_ep(send_cq);
+			ehea_reset_cq_n1(send_cq);
+			cqe = ehea_poll_cq(send_cq);
+			if (!cqe)
+				break;
+		}
+		cqe_counter++;
+		rmb();
+
+		if (netif_msg_tx_done(pr->port))
+			ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+		if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
+			   == EHEA_SWQE2_TYPE))
+			free_sent_skbs(cqe, pr);
+
+		swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
+		quota--;
+	} while (quota > 0);
+
+	ehea_update_feca(send_cq, cqe_counter);
+	atomic_add(swqe_av, &pr->swqe_avail);
+
+	if (unlikely(netif_queue_stopped(dev))) {
+		spin_lock_irqsave(&pr->netif_queue, flags);
+		if (unlikely((atomic_read(&pr->swqe_avail)
+			      >= EHEA_SWQE_REFILL_TH))) {
+			netif_wake_queue(pr->port->netdev);
+		}
+		spin_unlock_irqrestore(&pr->netif_queue, flags);
+	}
+
+	if (unlikely(cqe))
+		tasklet_hi_schedule(&pr->send_comp_task);
+}
+
+irqreturn_t ehea_send_irq_handler(int irq, void *param, struct pt_regs *regs)
+{
+	struct ehea_port_res *pr = (struct ehea_port_res*)param;
+	tasklet_hi_schedule(&pr->send_comp_task);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ehea_recv_irq_handler(int irq, void *param, struct pt_regs * regs)
+{
+	struct ehea_port_res *pr = (struct ehea_port_res*)param;
+	struct ehea_port *port = pr->port;
+	netif_rx_schedule(port->netdev);
+	return IRQ_HANDLED;
+}
+
+irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param, struct pt_regs * regs)
+{
+	struct ehea_port *port = (struct ehea_port*)param;
+	struct ehea_eqe *eqe;
+	u32 qp_token;
+
+	eqe = ehea_poll_eq(port->qp_eq);
+	ehea_debug("eqe=%p", eqe);
+	while (eqe) {
+		ehea_debug("*eqe=%lx", *(u64*)eqe);
+		eqe = ehea_poll_eq(port->qp_eq);
+		qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
+		ehea_debug("next eqe=%p", eqe);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
+				       int logical_port)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_ports; i++)
+		if (adapter->port[i]->logical_port_id == logical_port)
+			return adapter->port[i];
+	return NULL;
+}
+
+static int ehea_sense_port_attr(struct ehea_port *port)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	struct hcp_query_ehea_port_cb_0 *cb0 = NULL;
+
+	cb0 = kzalloc(sizeof(*cb0), GFP_KERNEL);
+	if (!cb0) {
+		ehea_error("no mem for cb0");
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	hret = ehea_h_query_ehea_port(port->adapter->handle,
+				      port->logical_port_id,
+				      H_PORT_CB0,
+				      EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF),
+				      cb0);
+	if (hret != H_SUCCESS) {
+		ret = -EPERM;
+		goto query_ehea_port_failed;
+	}
+
+	if (netif_msg_probe(port))
+		ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr");
+
+	/* MAC address */
+	port->mac_addr = cb0->port_mac_addr << 16;
+
+	/* Port speed */
+	switch (cb0->port_speed) {
+	case H_PORT_SPEED_10M_H:
+		port->port_speed = EHEA_SPEED_10M;
+		port->full_duplex = 0;
+		break;
+	case H_PORT_SPEED_10M_F:
+		port->port_speed = EHEA_SPEED_10M;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_100M_H:
+		port->port_speed = EHEA_SPEED_100M;
+		port->full_duplex = 0;
+		break;
+	case H_PORT_SPEED_100M_F:
+		port->port_speed = EHEA_SPEED_100M;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_1G_F:
+		port->port_speed = EHEA_SPEED_1G;
+		port->full_duplex = 1;
+		break;
+	case H_PORT_SPEED_10G_F:
+		port->port_speed = EHEA_SPEED_10G;
+		port->full_duplex = 1;
+		break;
+	default:
+		port->port_speed = 0;
+		port->full_duplex = 0;
+		break;
+	}
+
+	/* Number of default QPs */
+	port->num_def_qps = cb0->num_default_qps;
+	if (port->num_def_qps >= EHEA_NUM_TX_QP)
+		port->num_tx_qps = 0;
+	else
+		port->num_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+
+	ret = 0;
+
+query_ehea_port_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+	return ret;
+}
+
+
+static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
+{
+	int ret = -EINVAL;
+	u8 ec;
+	u8 portnum;
+	struct ehea_port *port;
+
+	ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+
+	switch (ec) {
+	case EHEA_EC_PORTSTATE_CHG:	/* port state change */
+		portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
+		port = ehea_get_port(adapter, portnum);
+
+		if (!port) {
+			ehea_error("unknown portnum %x", portnum);
+			break;
+		}
+
+		if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
+			if (!netif_carrier_ok(port->netdev)) {
+				ret = ehea_sense_port_attr(
+					adapter->port[portnum]);
+				if (ret) {
+					ehea_error("failed resensing port");
+					break;
+				}
+
+				if (netif_msg_link(port))
+					ehea_info("%s: Logical port up: %dMbps "
+						  "%s Duplex",
+						  port->netdev->name,
+						  port->port_speed,
+						  port->full_duplex ==
+						  1 ? "Full" : "Half");
+
+				netif_carrier_on(port->netdev);
+				netif_wake_queue(port->netdev);
+			}
+		} else
+			if (netif_carrier_ok(port->netdev)) {
+				if (netif_msg_link(port))
+					ehea_info("%s: Logical port down",
+						  port->netdev->name);
+				netif_carrier_off(port->netdev);
+				netif_stop_queue(port->netdev);
+			}
+
+		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+			if (netif_msg_link(port))
+				ehea_info("%s: Physical port up",
+					  port->netdev->name);
+		} else {
+			if (netif_msg_link(port))
+				ehea_info("%s: Physical port down",
+					  port->netdev->name);
+		}
+
+		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
+			ehea_info("Externel switch port is primary port");
+		else
+			ehea_info("Externel switch port is backup port");
+
+		break;
+	case EHEA_EC_ADAPTER_MALFUNC:	/* adapter malfunction */
+		ehea_error("adapter malfunction");
+		break;
+	case EHEA_EC_PORT_MALFUNC:	/* port malfunction */
+		ehea_info("Port malfunction");
+		/* TODO Determine the port structure of the malfunctioning port
+		 * netif_carrier_off(port->netdev);
+		 * netif_stop_queue(port->netdev);
+		 */
+		break;
+	default:
+		ehea_error("unknown event code %x", ec);
+		break;
+	}
+}
+
+void ehea_neq_tasklet(unsigned long data)
+{
+	struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+	struct ehea_eqe *eqe;
+	u64 event_mask;
+
+	eqe = ehea_poll_eq(adapter->neq);
+	ehea_debug("eqe=%p", eqe);
+
+	while (eqe) {
+		ehea_debug("*eqe=%lx", eqe->entry);
+		ehea_parse_eqe(adapter, eqe->entry);
+		eqe = ehea_poll_eq(adapter->neq);
+		ehea_debug("next eqe=%p", eqe);
+	}
+
+	event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
+		   | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1)
+		   | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1);
+
+	ehea_h_reset_events(adapter->handle,
+			    adapter->neq->fw_handle, event_mask);
+}
+
+irqreturn_t ehea_interrupt_neq(int irq, void *param, struct pt_regs *regs)
+{
+	struct ehea_adapter *adapter = (struct ehea_adapter*)param;
+	tasklet_hi_schedule(&adapter->neq_tasklet);
+	return IRQ_HANDLED;
+}
+
+
+static int ehea_fill_port_res(struct ehea_port_res *pr)
+{
+	int ret = 0;
+	struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
+
+	/* RQ 1 */
+	ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
+				 - init_attr->act_nr_rwqes_rq2
+				 - init_attr->act_nr_rwqes_rq3 - 1);
+	/* RQ 2 */
+	ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2);
+
+	/* RQ 3 */
+	ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3);
+
+	return ret;
+}
+
+static int ehea_reg_interrupts(struct net_device *dev)
+{
+	int ret = -EINVAL;
+	int i, k;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr;
+
+	for (i = 0; i < port->num_def_qps; i++) {
+		pr = &port->port_res[i];
+		snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
+			 , "%s-recv%d", dev->name, i);
+		ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
+					  ehea_recv_irq_handler,
+					  SA_INTERRUPT, pr->int_recv_name, pr);
+		if (ret) {
+			ehea_error("failed registering irq for ehea_recv_int:"
+				   "port_res_nr:%d, ist=%X", i,
+				   pr->recv_eq->attr.ist1);
+			for (k = 0; k < i; k++) {
+				u32 ist = port->port_res[k].recv_eq->attr.ist1;
+				ibmebus_free_irq(NULL, ist, &port->port_res[k]);
+			}
+			goto failure;
+		}
+		if (netif_msg_ifup(port))
+			ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
+				  "registered\n", pr->recv_eq->attr.ist1, i);
+	}
+
+	snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1,
+		 "%s-aff", dev->name);
+	ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
+				  ehea_qp_aff_irq_handler,
+				  SA_INTERRUPT, port->int_aff_name, port);
+	if (ret) {
+		ehea_error("failed registering irq for qp_aff_irq_handler:"
+			   " ist=%X", port->qp_eq->attr.ist1);
+		goto failure2;
+	}
+	if (netif_msg_ifup(port))
+		ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
+			  "registered\n", port->qp_eq->attr.ist1);
+
+	for (i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		pr = &port->port_res[i];
+		snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
+			 "%s-send%d", dev->name, i);
+		ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
+					  ehea_send_irq_handler,
+					  SA_INTERRUPT, pr->int_send_name,
+					  pr);
+		if (ret) {
+			ehea_error("failed registering irq for ehea_send"
+				   " port_res_nr:%d, ist=%X\n", i,
+				   pr->send_eq->attr.ist1);
+			for (k = 0; k < i; k++) {
+				u32 ist = port->port_res[k].send_eq->attr.ist1;
+				ibmebus_free_irq(NULL, ist, &port->port_res[i]);
+			}
+			goto failure3;
+		}
+		if (netif_msg_ifup(port))
+			ehea_info("irq_handle 0x%X for function ehea_send_int "
+				  "%d registered\n", pr->send_eq->attr.ist1, i);
+	}
+	return ret;
+failure3:
+	for (i = 0; i < port->num_def_qps; i++)
+		ibmebus_free_irq(NULL, port->port_res[i].recv_eq->attr.ist1,
+				 &port->port_res[i]);
+failure2:
+	ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+failure:
+	return ret;
+}
+
+static void ehea_free_interrupts(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	int i;
+
+	/* send */
+	for (i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ibmebus_free_irq(NULL, port->port_res[i].send_eq->attr.ist1,
+				 &port->port_res[i]);
+		if (netif_msg_intr(port))
+			ehea_info("free send irq for res %d with handle 0x%X",
+				  i, port->port_res[i].send_eq->attr.ist1);
+	}
+
+	/* receive */
+	for (i = 0; i < port->num_def_qps; i++) {
+		ibmebus_free_irq(NULL, port->port_res[i].recv_eq->attr.ist1,
+				 &port->port_res[i]);
+		if (netif_msg_intr(port))
+			ehea_info("free recv irq for res %d with handle 0x%X",
+				  i, port->port_res[i].recv_eq->attr.ist1);
+	}
+
+	/* associated events */
+	ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+	if (netif_msg_intr(port))
+		ehea_info("associated event interrupt for handle 0x%X freed",
+			  port->qp_eq->attr.ist1);
+}
+
+static int ehea_configure_port(struct ehea_port *port)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	struct hcp_query_ehea_port_cb_0 *cb0 = NULL;
+	u64 mask = 0;
+	int i;
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1)
+		     | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1)
+		     | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1)
+                     | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1)
+                     | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER,
+		                      PXLY_RC_VLAN_FILTER)
+		     | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
+
+	for (i = 0; i < port->num_def_qps; i++) {
+		cb0->default_qpn_array[i] =
+		    port->port_res[i].qp->init_attr.qp_nr;
+	}
+
+	if (netif_msg_ifup(port))
+		ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
+
+	mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1)
+	       | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1);
+
+	hret = ehea_h_modify_ehea_port(port->adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB0,
+				       mask,
+				       cb0);
+
+	if (hret != H_SUCCESS)
+		goto modify_ehea_port_failed;
+
+	ret = 0;
+
+modify_ehea_port_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+	return ret;
+}
+
+
+static int ehea_gen_smrs(struct ehea_port_res *pr)
+{
+	u64 hret = H_HARDWARE;
+	struct ehea_adapter *adapter = pr->port->adapter;
+
+	hret = ehea_h_register_smr(adapter->handle,
+				   adapter->mr.handle,
+				   adapter->mr.vaddr,
+				   EHEA_MR_ACC_CTRL,
+				   adapter->pd,
+				   &pr->send_mr);
+	if (hret != H_SUCCESS)
+		goto ehea_gen_smrs_err1;
+
+	hret = ehea_h_register_smr(adapter->handle,
+				   adapter->mr.handle,
+				   adapter->mr.vaddr,
+				   EHEA_MR_ACC_CTRL,
+				   adapter->pd,
+				   &pr->recv_mr);
+	if (hret != H_SUCCESS)
+		goto ehea_gen_smrs_err2;
+	return 0;
+
+ehea_gen_smrs_err2:
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->send_mr.handle);
+	if (hret != H_SUCCESS)
+		ehea_error("failed freeing SMR. hret:%lX\n", hret);
+ehea_gen_smrs_err1:
+	return -EINVAL;
+}
+
+static void ehea_rem_smrs(struct ehea_port_res *pr)
+{
+	u64 hret = H_HARDWARE;
+	struct ehea_adapter *adapter = pr->port->adapter;
+
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->send_mr.handle);
+	if (hret != H_SUCCESS)
+		ehea_error("failed freeing send SMR for pr=%p", pr);
+
+	hret = ehea_h_free_resource_mr(adapter->handle, pr->recv_mr.handle);
+	if (hret != H_SUCCESS)
+		ehea_error("failed freeing recv SMR for pr=%p", pr);
+}
+
+static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
+			      struct port_res_cfg *pr_cfg, int queue_token)
+{
+	int ret = -EINVAL;
+	int max_rq_entries = 0;
+	enum ehea_eq_type eq_type = EHEA_EQ;
+	struct ehea_qp_init_attr *init_attr = NULL;
+	struct ehea_adapter *adapter = port->adapter;
+
+	memset(pr, 0, sizeof(struct ehea_port_res));
+
+	pr->skb_arr_rq3 = NULL;
+	pr->skb_arr_rq2 = NULL;
+	pr->skb_arr_rq1 = NULL;
+	pr->skb_arr_sq = NULL;
+	pr->qp = NULL;
+	pr->send_cq = NULL;
+	pr->recv_cq = NULL;
+	pr->send_eq = NULL;
+	pr->recv_eq = NULL;
+
+	pr->port = port;
+	spin_lock_init(&pr->send_lock);
+	spin_lock_init(&pr->recv_lock);
+	spin_lock_init(&pr->xmit_lock);
+	spin_lock_init(&pr->netif_queue);
+
+	pr->recv_eq = ehea_create_eq(adapter, eq_type,
+				     EHEA_MAX_ENTRIES_EQ, 0);
+	if (!pr->recv_eq) {
+		ehea_error("create_eq failed (recv_eq)");
+		goto ehea_init_port_res_err;
+	}
+	pr->send_eq = ehea_create_eq(adapter, eq_type,
+				     EHEA_MAX_ENTRIES_EQ, 0);
+	if (!pr->send_eq) {
+		ehea_error("create_eq failed (send_eq)");
+		goto ehea_init_port_res_err;
+	}
+
+	pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
+				     pr->recv_eq->fw_handle,
+				     port->logical_port_id);
+	if (!pr->recv_cq) {
+		ehea_error("create_cq failed (cq_recv)");
+		goto ehea_init_port_res_err;
+	}
+
+	pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
+				     pr->send_eq->fw_handle,
+				     port->logical_port_id);
+	if (!pr->send_cq) {
+		ehea_error("create_cq failed (cq_send)");
+		goto ehea_init_port_res_err;
+	}
+
+	init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
+
+	if (!init_attr) {
+		ret = -ENOMEM;
+		ehea_error("no mem");
+		goto ehea_init_port_res_err;
+	}
+
+	init_attr->low_lat_rq1 = 1;
+	init_attr->signalingtype = 1;	/* generate CQE if specified in WQE */
+	init_attr->rq_count = 3;
+	init_attr->qp_token = queue_token;
+
+	init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq;
+	init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1;
+	init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2;
+	init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3;
+
+	init_attr->wqe_size_enc_sq = EHEA_SG_SQ;
+	init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1;
+	init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2;
+	init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3;
+
+	init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD;
+	init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD;
+	init_attr->port_nr = port->logical_port_id;
+	init_attr->send_cq_handle = pr->send_cq->fw_handle;
+	init_attr->recv_cq_handle = pr->recv_cq->fw_handle;
+	init_attr->aff_eq_handle = port->qp_eq->fw_handle;
+
+	pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
+	if (!pr->qp) {
+		ehea_error("create_qp failed");
+		goto ehea_init_port_res_err;
+	}
+
+	if (netif_msg_ifup(port))
+		ehea_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n "
+			  "nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d\n", init_attr->qp_nr,
+			  init_attr->act_nr_send_wqes,
+			  init_attr->act_nr_rwqes_rq1,
+			  init_attr->act_nr_rwqes_rq2,
+			  init_attr->act_nr_rwqes_rq3);
+
+	/* SQ */
+	max_rq_entries = init_attr->act_nr_send_wqes + 1;
+	pr->skb_arr_sq = vmalloc(sizeof(struct sk_buff*)
+				 * max_rq_entries);
+	if (!pr->skb_arr_sq) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_sq, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_sq_index = 0;
+	pr->skb_arr_sq_len = max_rq_entries;
+
+	/* RQ 1 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq1 + 1;
+	pr->skb_arr_rq1 = vmalloc(sizeof(struct sk_buff*)
+				  * max_rq_entries);
+	if (!pr->skb_arr_rq1) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq1, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq1_len = max_rq_entries;
+
+	/* RQ 2 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq2 + 1;
+	pr->skb_arr_rq2 = vmalloc(sizeof(struct sk_buff*)*max_rq_entries);
+	if (!pr->skb_arr_rq2) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq2, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq2_len = max_rq_entries;
+	pr->skb_rq2_index = 0;
+
+	/* RQ 3 */
+	max_rq_entries = init_attr->act_nr_rwqes_rq3 + 1;
+	pr->skb_arr_rq3 = vmalloc(sizeof(struct sk_buff*)
+				  * max_rq_entries);
+	if (!pr->skb_arr_rq3) {
+		ret = -ENOMEM;
+		goto ehea_init_port_res_err;
+	}
+	memset(pr->skb_arr_rq3, 0, sizeof(void*) * max_rq_entries);
+	pr->skb_arr_rq3_len = max_rq_entries;
+	pr->skb_rq3_index = 0;
+
+	if (ehea_gen_smrs(pr) != 0)
+		goto ehea_init_port_res_err;
+	tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
+		     (unsigned long)pr);
+	atomic_set(&pr->swqe_avail, EHEA_MAX_ENTRIES_SQ - 1);
+
+	kfree(init_attr);
+	ret = 0;
+	goto done;
+
+ehea_init_port_res_err:
+	vfree(pr->skb_arr_rq3);
+	vfree(pr->skb_arr_rq2);
+	vfree(pr->skb_arr_rq1);
+	vfree(pr->skb_arr_sq);
+	ehea_destroy_qp(pr->qp);
+	kfree(init_attr);
+	ehea_destroy_cq(pr->send_cq);
+	ehea_destroy_cq(pr->recv_cq);
+	ehea_destroy_eq(pr->send_eq);
+	ehea_destroy_eq(pr->recv_eq);
+done:
+	return ret;
+}
+
+static int ehea_clean_port_res(struct ehea_port *port, struct ehea_port_res *pr)
+{
+	int i;
+	int ret = -EINVAL;
+
+	ehea_destroy_qp(pr->qp);
+	ehea_destroy_cq(pr->send_cq);
+	ehea_destroy_cq(pr->recv_cq);
+	ehea_destroy_eq(pr->send_eq);
+	ehea_destroy_eq(pr->recv_eq);
+
+	for (i = 0; i < pr->skb_arr_rq1_len; i++) {
+		if (pr->skb_arr_rq1[i])
+			dev_kfree_skb(pr->skb_arr_rq1[i]);
+	}
+
+	for (i = 0; i < pr->skb_arr_rq2_len; i++)
+		if (pr->skb_arr_rq2[i])
+			dev_kfree_skb(pr->skb_arr_rq2[i]);
+
+	for (i = 0; i < pr->skb_arr_rq3_len; i++)
+		if (pr->skb_arr_rq3[i])
+			dev_kfree_skb(pr->skb_arr_rq3[i]);
+
+	for (i = 0; i < pr->skb_arr_sq_len; i++)
+		if (pr->skb_arr_sq[i])
+			dev_kfree_skb(pr->skb_arr_sq[i]);
+
+	vfree(pr->skb_arr_sq);
+	vfree(pr->skb_arr_rq1);
+	vfree(pr->skb_arr_rq2);
+	vfree(pr->skb_arr_rq3);
+
+	ehea_rem_smrs(pr);
+	return ret;
+}
+
+/*
+ * The write_* functions store information in swqe which is used by
+ * the hardware to calculate the ip/tcp/udp checksum
+ */
+
+static inline void write_ip_start_end(struct ehea_swqe *swqe,
+				      const struct sk_buff *skb)
+{
+
+	swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data));
+	swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1);
+}
+
+static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
+					const struct sk_buff *skb)
+{
+	swqe->tcp_offset = (u8)(swqe->ip_end + 1 + offsetof(struct tcphdr,
+							    check));
+	swqe->tcp_end = (u16)skb->len - 1;
+}
+
+static inline void write_udp_offset_end(struct ehea_swqe *swqe,
+					const struct sk_buff *skb)
+{
+	swqe->tcp_offset = (u8)(swqe->ip_end + 1 + offsetof(struct udphdr,
+							    check));
+	swqe->tcp_end = (u16)skb->len - 1;
+}
+
+static inline void write_swqe2_data(struct sk_buff *skb,
+				    struct net_device *dev,
+				    struct ehea_swqe *swqe,
+				    u32 lkey)
+{
+	int skb_data_size, nfrags, headersize, i, sg1entry_contains_frag_data;
+	struct ehea_vsgentry *sg_list;
+	struct ehea_vsgentry *sg1entry;
+	struct ehea_vsgentry *sgentry;
+	u8 *imm_data;
+	u64 tmp_addr;
+	skb_frag_t *frag;
+
+	skb_data_size = skb->len - skb->data_len;
+	nfrags = skb_shinfo(skb)->nr_frags;
+	sg1entry = &swqe->u.immdata_desc.sg_entry;
+	sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+	imm_data = &swqe->u.immdata_desc.immediate_data[0];
+	swqe->descriptors = 0;
+	sg1entry_contains_frag_data = 0;
+
+	if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size) {
+		/* Packet is TCP with TSO enabled */
+		swqe->tx_control |= EHEA_SWQE_TSO;
+		swqe->mss = skb_shinfo(skb)->gso_size;
+		/* copy only eth/ip/tcp headers to immediate data and
+		 * the rest of skb->data to sg1entry
+		 */
+		headersize = ETH_HLEN + (skb->nh.iph->ihl * 4)
+				      + (skb->h.th->doff * 4);
+
+		skb_data_size = skb->len - skb->data_len;
+
+		if (skb_data_size >= headersize) {
+			/* copy immediate data */
+			memcpy(imm_data, skb->data, headersize);
+			swqe->immediate_data_length = headersize;
+
+			if (skb_data_size > headersize) {
+				/* set sg1entry data */
+				sg1entry->l_key = lkey;
+				sg1entry->len = skb_data_size - headersize;
+
+				tmp_addr = (u64)(skb->data + headersize);
+				sg1entry->vaddr = tmp_addr;
+				swqe->descriptors++;
+			}
+		} else
+			ehea_error("cannot handle fragmented headers");
+	} else {
+		/* Packet is any nonTSO type
+		 *
+		 * Copy as much as possible skb->data to immediate data and
+		 * the rest to sg1entry
+		 */
+		if (skb_data_size >= SWQE2_MAX_IMM) {
+			/* copy immediate data */
+			memcpy(imm_data, skb->data, SWQE2_MAX_IMM);
+
+			swqe->immediate_data_length = SWQE2_MAX_IMM;
+
+			if (skb_data_size > SWQE2_MAX_IMM) {
+				/* copy sg1entry data */
+				sg1entry->l_key = lkey;
+				sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
+				tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
+				sg1entry->vaddr = tmp_addr;
+				swqe->descriptors++;
+			}
+		} else {
+			memcpy(imm_data, skb->data, skb_data_size);
+			swqe->immediate_data_length = skb_data_size;
+		}
+	}
+
+	/* write descriptors */
+	if (nfrags > 0) {
+		if (swqe->descriptors == 0) {
+			/* sg1entry not yet used */
+			frag = &skb_shinfo(skb)->frags[0];
+
+			/* copy sg1entry data */
+			sg1entry->l_key = lkey;
+			sg1entry->len = frag->size;
+			tmp_addr =  (u64)(page_address(frag->page)
+					  + frag->page_offset);
+			sg1entry->vaddr = tmp_addr;
+			swqe->descriptors++;
+			sg1entry_contains_frag_data = 1;
+		}
+
+		for (i = sg1entry_contains_frag_data; i < nfrags; i++) {
+
+			frag = &skb_shinfo(skb)->frags[i];
+			sgentry = &sg_list[i - sg1entry_contains_frag_data];
+
+			sgentry->l_key = lkey;
+			sgentry->len = frag->size;
+
+			tmp_addr = (u64)(page_address(frag->page)
+					 + frag->page_offset);
+			sgentry->vaddr = tmp_addr;
+		}
+	}
+}
+
+static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
+{
+	u64 hret = H_HARDWARE;
+	u8 reg_type = 0;
+	int ret = 0;
+
+	/* De/Register untagged packets */
+	reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED;
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, port->mac_addr, 0, hcallid);
+	if (hret != H_SUCCESS) {
+		ehea_error("reg_dereg_bcmc failed (tagged)");
+		ret = -EOPNOTSUPP;
+		goto hcall_failed;
+	}
+
+	/* De/Register VLAN packets */
+	reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL;
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, port->mac_addr, 0, hcallid);
+	if (hret != H_SUCCESS) {
+		ehea_error("reg_dereg_bcmc failed (vlan)");
+		ret = -EOPNOTSUPP;
+	}
+hcall_failed:
+	return ret;
+}
+
+static int ehea_set_mac_addr(struct net_device *dev, void *sa)
+{
+	int ret = -EOPNOTSUPP;
+	u64 hret = H_HARDWARE;
+	struct hcp_query_ehea_port_cb_0 *cb0 = NULL;
+	struct ehea_port *port = netdev_priv(dev);
+	struct sockaddr *mac_addr = (struct sockaddr*)sa;
+
+	if (!is_valid_ether_addr(mac_addr->sa_data)) {
+		ret = -EADDRNOTAVAIL;
+		goto invalid_mac;
+	}
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ehea_error("no mem for cb0");
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN);
+
+	cb0->port_mac_addr = cb0->port_mac_addr >> 16;
+
+	hret = ehea_h_modify_ehea_port(port->adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB0,
+				       EHEA_BMASK_SET(H_PORT_CB0_MAC, 1),
+				       cb0);
+	if (hret != H_SUCCESS) {
+		ret = -EOPNOTSUPP;
+		goto hcall_failed;
+	}
+
+	memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
+
+	/* Deregister old MAC in pHYP */
+	ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+	if (ret)
+		goto hcall_failed;
+
+	port->mac_addr = cb0->port_mac_addr << 16;
+
+	/* Register new MAC in pHYP */
+	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+	if (ret)
+		goto hcall_failed;
+
+	ret = 0;
+
+hcall_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+invalid_mac:
+	return ret;
+}
+
+static void ehea_promiscuous(struct net_device *dev, int enable)
+{
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (!port->promisc) {
+		if (enable) {
+			/* Enable promiscuous mode */
+			ehea_error("Enable promiscuous mode: "
+				   "not yet implemented");
+			port->promisc = 1;
+		}
+	} else {
+		if (!enable) {
+			/* Disable promiscuous mode */
+			ehea_error("Disable promiscuous mode: "
+				   "not yet implemented");
+			port->promisc = 0;
+		}
+	}
+}
+
+static u64 ehea_multicast_reg_helper(struct ehea_port *port,
+				     u64 mc_mac_addr,
+				     u32 hcallid)
+{
+	u64 hret = H_HARDWARE;
+	u8 reg_type = 0;
+
+	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+		 | EHEA_BCMC_UNTAGGED;
+
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, mc_mac_addr, 0, hcallid);
+	if (hret)
+		goto hcall_failed;
+
+	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+		 | EHEA_BCMC_VLANID_ALL;
+
+	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+				     port->logical_port_id,
+				     reg_type, mc_mac_addr, 0, hcallid);
+hcall_failed:
+	return hret;
+}
+
+static int ehea_drop_multicast_list(struct net_device *dev)
+{
+	int ret = 0;
+	u64 hret = H_HARDWARE;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_mc_list *mc_entry = port->mc_list;
+	struct list_head *pos;
+	struct list_head *temp;
+
+	list_for_each_safe(pos, temp, &(port->mc_list->list)) {
+		mc_entry = list_entry(pos, struct ehea_mc_list, list);
+
+		hret = ehea_multicast_reg_helper(port,
+						 mc_entry->macaddr,
+						 H_DEREG_BCMC);
+		if (hret) {
+			ehea_error("failed deregistering mcast MAC");
+			ret = -EINVAL;
+		}
+
+		list_del(pos);
+		kfree(mc_entry);
+	}
+	return ret;
+}
+
+static void ehea_allmulti(struct net_device *dev, int enable)
+{
+	u64 hret = H_HARDWARE;
+	struct ehea_port *port = netdev_priv(dev);
+
+	if (!port->allmulti) {
+		if (enable) {
+			/* Enable ALLMULTI */
+			ehea_drop_multicast_list(dev);
+			hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC);
+			if (!hret)
+				port->allmulti = 1;
+			else
+				ehea_error("failed enabling IFF_ALLMULTI");
+		}
+	} else
+		if (!enable) {
+			/* Disable ALLMULTI */
+			hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
+			if (!hret)
+				port->allmulti = 0;
+			else
+				ehea_error("failed disabling IFF_ALLMULTI");
+		}
+}
+
+static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+{
+	u64 hret = H_HARDWARE;
+	struct ehea_mc_list *ehea_mcl_entry;
+
+	ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_KERNEL);
+	if (!ehea_mcl_entry) {
+		ehea_error("no mem for mcl_entry");
+		return;
+	}
+
+	INIT_LIST_HEAD(&ehea_mcl_entry->list);
+
+	memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN);
+
+	hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr,
+					 H_REG_BCMC);
+	if (!hret)
+		list_add(&ehea_mcl_entry->list, &port->mc_list->list);
+	else {
+		ehea_error("failed registering mcast MAC");
+		kfree(ehea_mcl_entry);
+	}
+}
+
+static void ehea_set_multicast_list(struct net_device *dev)
+{
+	int ret;
+	int i;
+	struct ehea_port *port = netdev_priv(dev);
+	struct dev_mc_list *k_mcl_entry;
+
+	if (dev->flags & IFF_PROMISC) {
+		ehea_promiscuous(dev, 1);
+		return;
+	}
+	ehea_promiscuous(dev, 0);
+
+	if (dev->flags & IFF_ALLMULTI) {
+		ehea_allmulti(dev, 1);
+		return;
+	}
+	ehea_allmulti(dev, 0);
+
+	if (dev->mc_count) {
+		ret = ehea_drop_multicast_list(dev);
+		if (ret) {
+			/* Dropping the current multicast list failed.
+			 * Enabling ALL_MULTI is the best we can do.
+			 */
+			ehea_allmulti(dev, 1);
+		}
+
+		if (dev->mc_count > port->adapter->max_mc_mac) {
+			ehea_info("Mcast registration limit reached (0x%lx). "
+				  "Use ALLMULTI!",
+				  port->adapter->max_mc_mac);
+			goto escape;
+		}
+
+		for (i = 0, k_mcl_entry = dev->mc_list;
+		     i < dev->mc_count;
+		     i++, k_mcl_entry = k_mcl_entry->next) {
+			ehea_add_multicast_entry(port,
+						 k_mcl_entry->dmi_addr);
+		}
+	}
+escape:
+	return;
+}
+
+static int ehea_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > EHEA_MAX_PACKET_SIZE))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static inline void ehea_xmit2(struct sk_buff *skb,
+			      struct net_device *dev, struct ehea_swqe *swqe,
+			      u32 lkey)
+{
+	int nfrags;
+	nfrags = skb_shinfo(skb)->nr_frags;
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		/* IPv4 */
+		swqe->tx_control |= EHEA_SWQE_CRC
+				 | EHEA_SWQE_IP_CHECKSUM
+				 | EHEA_SWQE_TCP_CHECKSUM
+				 | EHEA_SWQE_IMM_DATA_PRESENT
+				 | EHEA_SWQE_DESCRIPTORS_PRESENT;
+
+		write_ip_start_end(swqe, skb);
+
+		if (skb->nh.iph->protocol == IPPROTO_UDP) {
+			if ((skb->nh.iph->frag_off & IP_MF)
+			    || (skb->nh.iph->frag_off & IP_OFFSET))
+				/* IP fragment, so don't change cs */
+				swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
+			else
+				write_udp_offset_end(swqe, skb);
+
+		} else if (skb->nh.iph->protocol == IPPROTO_TCP) {
+			write_tcp_offset_end(swqe, skb);
+		}
+
+		/* icmp (big data) and ip segmentation packets (all other ip
+		   packets) do not require any special handling */
+
+	} else {
+		/* Other Ethernet Protocol */
+		swqe->tx_control |= EHEA_SWQE_CRC
+				 | EHEA_SWQE_IMM_DATA_PRESENT
+				 | EHEA_SWQE_DESCRIPTORS_PRESENT;
+	}
+
+	write_swqe2_data(skb, dev, swqe, lkey);
+}
+
+static inline void ehea_xmit3(struct sk_buff *skb,
+			      struct net_device *dev, struct ehea_swqe *swqe)
+{
+	int i;
+	skb_frag_t *frag;
+	int nfrags = skb_shinfo(skb)->nr_frags;
+	u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
+
+	if (likely(skb->protocol == htons(ETH_P_IP))) {
+		/* IPv4 */
+		write_ip_start_end(swqe, skb);
+
+		if (skb->nh.iph->protocol == IPPROTO_TCP) {
+			swqe->tx_control |= EHEA_SWQE_CRC
+					 | EHEA_SWQE_IP_CHECKSUM
+					 | EHEA_SWQE_TCP_CHECKSUM
+					 | EHEA_SWQE_IMM_DATA_PRESENT;
+
+			write_tcp_offset_end(swqe, skb);
+
+		} else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+			if ((skb->nh.iph->frag_off & IP_MF)
+			    || (skb->nh.iph->frag_off & IP_OFFSET))
+				/* IP fragment, so don't change cs */
+				swqe->tx_control |= EHEA_SWQE_CRC
+						 | EHEA_SWQE_IMM_DATA_PRESENT;
+			else {
+				swqe->tx_control |= EHEA_SWQE_CRC
+						 | EHEA_SWQE_IP_CHECKSUM
+						 | EHEA_SWQE_TCP_CHECKSUM
+						 | EHEA_SWQE_IMM_DATA_PRESENT;
+
+				write_udp_offset_end(swqe, skb);
+			}
+		} else {
+			/* icmp (big data) and
+			   ip segmentation packets (all other ip packets) */
+			swqe->tx_control |= EHEA_SWQE_CRC
+					 | EHEA_SWQE_IP_CHECKSUM
+					 | EHEA_SWQE_IMM_DATA_PRESENT;
+		}
+	} else {
+		/* Other Ethernet Protocol */
+		swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
+	}
+	/* copy (immediate) data */
+	if (nfrags == 0) {
+		/* data is in a single piece */
+		memcpy(imm_data, skb->data, skb->len);
+	} else {
+		/* first copy data from the skb->data buffer ... */
+		memcpy(imm_data, skb->data, skb->len - skb->data_len);
+		imm_data += skb->len - skb->data_len;
+
+		/* ... then copy data from the fragments */
+		for (i = 0; i < nfrags; i++) {
+			frag = &skb_shinfo(skb)->frags[i];
+			memcpy(imm_data,
+			       page_address(frag->page) + frag->page_offset,
+			       frag->size);
+			imm_data += frag->size;
+		}
+	}
+	swqe->immediate_data_length = skb->len;
+	dev_kfree_skb(skb);
+}
+
+static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned long flags;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_port_res *pr;
+	struct ehea_swqe *swqe;
+	u32 lkey;
+	int swqe_index;
+
+	pr = &port->port_res[0];
+
+	if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+		spin_lock_irqsave(&pr->netif_queue, flags);
+		if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+			netif_stop_queue(dev);
+			spin_unlock_irqrestore(&pr->netif_queue, flags);
+			return NETDEV_TX_BUSY;
+		}
+		spin_unlock_irqrestore(&pr->netif_queue, flags);
+	}
+	atomic_dec(&pr->swqe_avail);
+
+	spin_lock(&pr->xmit_lock);
+
+	swqe = ehea_get_swqe(pr->qp, &swqe_index);
+	memset(swqe, 0, 32);
+
+	if (skb->len <= SWQE3_MAX_IMM) {
+		u32 swqe_num = pr->swqe_id_counter;
+		ehea_xmit3(skb, dev, swqe);
+		swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_REFILL, EHEA_SIG_IV)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num);
+		if (pr->swqe_ll_count >= (EHEA_SIG_IV - 1)) {
+			swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+			pr->swqe_ll_count = 0;
+		} else
+			pr->swqe_ll_count += 1;
+	} else {
+		swqe->wr_id =
+		    EHEA_BMASK_SET(EHEA_WR_ID_REFILL, EHEA_SIG_IV_LONG)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
+		    | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->skb_sq_index);
+		pr->skb_arr_sq[pr->skb_sq_index] = skb;
+
+		pr->skb_sq_index++;
+		pr->skb_sq_index &= (pr->skb_arr_sq_len - 1);
+
+		lkey = pr->send_mr.lkey;
+		ehea_xmit2(skb, dev, swqe, lkey);
+
+		if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
+			swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+			pr->swqe_count = 0;
+		} else
+			pr->swqe_count += 1;
+	}
+	pr->swqe_id_counter += 1;
+
+	if (port->vgrp && vlan_tx_tag_present(skb)) {
+		swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
+		swqe->vlan_tag = vlan_tx_tag_get(skb);
+	}
+
+	if (netif_msg_tx_queued(port)) {
+		ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
+		ehea_dump(swqe, sizeof(*swqe), "swqe");
+	}
+
+	ehea_post_swqe(pr->qp, swqe);
+	pr->tx_packets++;
+	spin_unlock(&pr->xmit_lock);
+
+	return NETDEV_TX_OK;
+}
+
+static void ehea_vlan_rx_register(struct net_device *dev,
+				  struct vlan_group *grp)
+{
+	u64 hret = H_HARDWARE;
+	struct hcp_query_ehea_port_cb_1 *cb1 = NULL;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+
+	port->vgrp = grp;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_reg_exit;
+	}
+
+	if (grp)
+		memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
+	else
+		memset(cb1->vlan_filter, 1, sizeof(cb1->vlan_filter));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB1,
+				       H_PORT_CB1_ALL,
+				       cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_reg_exit:
+	return;
+}
+
+static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+	int index;
+	u64 hret = H_HARDWARE;
+	struct ehea_port *port = netdev_priv(dev);
+	struct hcp_query_ehea_port_cb_1 *cb1 = NULL;
+	struct ehea_adapter *adapter = port->adapter;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_kill_exit;
+	}
+
+	hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+				      H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto vlan_kill_exit;
+	}
+
+	index = (vid / 64);
+	cb1->vlan_filter[index] |= ((u64)(1 << (vid & 0x3F)));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+				       H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_kill_exit:
+	return;
+
+}
+
+static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	int index;
+	u64 hret = H_HARDWARE;
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_query_ehea_port_cb_1 *cb1 = NULL;
+
+	if (port->vgrp)
+		port->vgrp->vlan_devices[vid] = NULL;
+
+	cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb1) {
+		ehea_error("no mem for cb1");
+		goto vlan_kill_exit;
+	}
+	hret = ehea_h_query_ehea_port(adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB1,
+				       H_PORT_CB1_ALL,
+				       cb1);
+
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_port failed");
+		goto vlan_kill_exit;
+	}
+
+	index = (vid / 64);
+	cb1->vlan_filter[index] &= ~((u64)(1 << (vid & 0x3F)));
+
+	hret = ehea_h_modify_ehea_port(adapter->handle,
+				       port->logical_port_id,
+				       H_PORT_CB1,
+				       H_PORT_CB1_ALL,
+				       cb1);
+	if (hret != H_SUCCESS)
+		ehea_error("modify_ehea_port failed");
+
+	kfree(cb1);
+
+vlan_kill_exit:
+	return;
+}
+
+int ehea_stop_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	u16 dummy16;
+	u64 dummy64;
+	struct hcp_modify_qp_cb_0 *cb0 = NULL;
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+
+	if (!cb0) {
+		ehea_error("no mem for cb0");
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	/* Reset queue pair */
+	cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RESET;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("gailed resetting the queue pair");
+		goto modify_qp_failed;
+	}
+
+	/* Disable queue pair */
+	cb0->qp_ctl_reg = H_QP_CR_STATE_RESET;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("failed disabling the queue pair");
+		goto modify_qp_failed;
+	}
+
+	ret = 0;
+
+modify_qp_failed:
+	kfree(cb0);
+
+kzalloc_failed:
+	return ret;
+}
+
+int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	u16 dummy16 = 0;
+	u64 dummy64 = 0;
+	struct hcp_modify_qp_cb_0* cb0 = NULL;
+
+	cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (1)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (1)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (2)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (2)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (3)");
+		goto failure;
+	}
+
+	cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND;
+	hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+				     &dummy64, &dummy64, &dummy16, &dummy16);
+	if (hret != H_SUCCESS) {
+		ehea_error("modify_ehea_qp failed (3)");
+		goto failure;
+	}
+
+	hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+				    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+	if (hret != H_SUCCESS) {
+		ehea_error("query_ehea_qp failed (4)");
+		goto failure;
+	}
+
+	ret = 0;
+
+failure:
+	kfree(cb0);
+	return ret;
+}
+
+static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
+			       int add_tx_qps)
+{
+	int i, k;
+	int ret = 0;
+	struct port_res_cfg pr_cfg, pr_cfg_small_rx;
+	enum ehea_eq_type eq_type = EHEA_EQ;
+
+	port->qp_eq = ehea_create_eq(port->adapter, eq_type,
+				   EHEA_MAX_ENTRIES_EQ, 1);
+	if (!port->qp_eq) {
+		ehea_error("ehea_create_eq failed (qp_eq)");
+		goto port_res_setup_failed2;
+	}
+
+	pr_cfg.max_entries_rcq = EHEA_MAX_CQE_COUNT;
+	pr_cfg.max_entries_scq = EHEA_MAX_CQE_COUNT;
+	pr_cfg.max_entries_sq = EHEA_MAX_ENTRIES_SQ;
+	pr_cfg.max_entries_rq1 = EHEA_MAX_ENTRIES_RQ1;
+	pr_cfg.max_entries_rq2 = EHEA_MAX_ENTRIES_RQ2;
+	pr_cfg.max_entries_rq3 = EHEA_MAX_ENTRIES_RQ3;
+
+	pr_cfg_small_rx.max_entries_rcq = 1;
+	pr_cfg_small_rx.max_entries_scq = EHEA_MAX_CQE_COUNT;
+	pr_cfg_small_rx.max_entries_sq = EHEA_MAX_ENTRIES_SQ;
+	pr_cfg_small_rx.max_entries_rq1 = 1;
+	pr_cfg_small_rx.max_entries_rq2 = 1;
+	pr_cfg_small_rx.max_entries_rq3 = 1;
+
+
+	for (i = 0; i < def_qps; i++) {
+		ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i);
+		if (ret)
+			goto port_res_setup_failed;
+	}
+	for (i = def_qps; i < def_qps + add_tx_qps; i++) {
+		ret = ehea_init_port_res(port, &port->port_res[i],
+					 &pr_cfg_small_rx, i);
+		if (ret)
+			goto port_res_setup_failed;
+	}
+	return 0;
+
+port_res_setup_failed:
+	for(k = 0; k < i; k++) {
+		ehea_clean_port_res(port, &port->port_res[k]);
+	}
+port_res_setup_failed2:
+	ehea_destroy_eq(port->qp_eq);
+	return ret;
+}
+
+void ehea_clean_all_port_res(struct ehea_port *port)
+{
+	int ret;
+	int i;
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++)
+		ehea_clean_port_res(port, &port->port_res[i]);
+
+	ret = ehea_destroy_eq(port->qp_eq);
+}
+
+int ehea_open(struct net_device *dev)
+{
+	int i;
+	int ret = -EIO;
+	struct ehea_port *port = netdev_priv(dev);
+	u64 mac_addr = 0;
+
+	ret = ehea_port_res_setup(port, port->num_def_qps, port->num_tx_qps);
+	if (ret)
+		goto port_res_setup_failed;
+
+	/* Set default QP for this port */
+	ret = ehea_configure_port(port);
+	if (ret) {
+		ehea_error("ehea_configure_port failed. ret:%d", ret);
+		goto reg_failed;
+	}
+
+	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+	if (ret) {
+		ret = -EIO;
+		goto reg_failed;
+	}
+	mac_addr = (*(u64*)dev->dev_addr) >> 16;
+
+	ret = ehea_reg_interrupts(dev);
+	if (ret)
+		goto irq_reg_failed;
+
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
+		if (ret)
+			goto activate_qp_failed;
+	}
+
+	for(i = 0; i < port->num_def_qps + port->num_tx_qps; i++) {
+		ret = ehea_fill_port_res(&port->port_res[i]);
+		if (ret)
+			goto fill_port_res_failed;
+	}
+
+	netif_start_queue(dev);
+	ret = 0;
+	goto done;
+
+fill_port_res_failed:
+activate_qp_failed:
+	ehea_free_interrupts(dev);
+
+irq_reg_failed:
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
+reg_failed:
+	ehea_clean_all_port_res(port);
+
+port_res_setup_failed:
+done:
+	return ret;
+}
+
+static int ehea_stop(struct net_device *dev)
+{
+	int ret;
+	struct ehea_port *port = netdev_priv(dev);
+
+	netif_stop_queue(dev);
+	ehea_drop_multicast_list(dev);
+	ret = ehea_stop_qp(port->adapter, port->port_res[0].qp);
+	ehea_free_interrupts(dev);
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+	if (!ret)
+		ehea_clean_all_port_res(port);
+	return ret;
+}
+
+int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	struct hcp_query_ehea *cb = NULL;
+
+	cb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb) {
+		ret = -ENOMEM;
+		goto kzalloc_failed;
+	}
+
+	hret = ehea_h_query_ehea(adapter->handle, cb);
+
+	if (hret != H_SUCCESS)
+		goto query_ehea_failed;
+
+	adapter->num_ports = cb->num_ports;
+	adapter->max_mc_mac = cb->max_mc_mac - 1;
+	ret = 0;
+
+query_ehea_failed:
+	kfree(cb);
+
+kzalloc_failed:
+	return ret;
+}
+
+static int ehea_setup_single_port(struct ehea_port *port,
+				  struct device_node *dn)
+{
+	int ret = -EINVAL;
+	u64 hret = H_HARDWARE;
+	struct net_device *dev = port->netdev;
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_query_ehea_port_cb_4 *cb4;
+	u32 *dn_log_port_id = NULL;
+
+	if (!dn) {
+		ehea_error("bad device node: dn=%p", dn);
+		ret = -EINVAL;
+		goto done;
+	}
+
+	port->of_dev_node = dn;
+
+	/* Determine logical port id */
+	dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
+
+	if (!dn_log_port_id) {
+		ehea_error("bad device node: dn_log_port_id=%p",
+		       dn_log_port_id);
+		ret = -EINVAL;
+		goto done;
+	}
+	port->logical_port_id = *dn_log_port_id;
+
+	port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+	if (!port->mc_list) {
+		ret = -ENOMEM;
+		goto done;
+	}
+
+	INIT_LIST_HEAD(&port->mc_list->list);
+
+	ret = ehea_sense_port_attr(port);
+	if (ret)
+		goto done;
+
+	/* Enable Jumbo frames */
+	cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+	if (!cb4) {
+		ehea_error("no mem for cb4");
+	} else {
+		cb4->jumbo_frame = 1;
+		hret = ehea_h_modify_ehea_port(adapter->handle,
+					       port->logical_port_id,
+					       H_PORT_CB4,
+					       H_PORT_CB4_JUMBO,
+					       cb4);
+		if (hret != H_SUCCESS) {
+			ehea_error("modify_ehea_port failed");
+			ehea_info("Jumbo frames not activated");
+		}
+		kfree(cb4);
+	}
+
+	/* initialize net_device structure */
+	SET_MODULE_OWNER(dev);
+
+	memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
+
+	dev->open = ehea_open;
+	dev->poll = ehea_poll;
+	dev->weight = 64;
+	dev->stop = ehea_stop;
+	dev->hard_start_xmit = ehea_start_xmit;
+	dev->get_stats = ehea_get_stats;
+	dev->set_multicast_list = ehea_set_multicast_list;
+	dev->set_mac_address = ehea_set_mac_addr;
+	dev->change_mtu = ehea_change_mtu;
+	dev->vlan_rx_register = ehea_vlan_rx_register;
+	dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid;
+	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+		      | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX
+		      | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
+		      | NETIF_F_LLTX;
+
+	ehea_set_ethtool_ops(dev);
+
+	ret = register_netdev(dev);
+	if (ret) {
+		ehea_error("register_netdev failed. ret=%d", ret);
+		goto reg_netdev_failed;
+	}
+
+	port->netdev = dev;
+	ret = 0;
+	goto done;
+
+reg_netdev_failed:
+	kfree(port->mc_list);
+done:
+	return ret;
+}
+
+static int ehea_setup_ports(struct ehea_adapter *adapter)
+{
+	int ret = -EINVAL;
+	int i;
+	int port_setup_ok = 0;
+	struct ehea_port *port = NULL;
+	struct device_node *dn = NULL;
+	struct net_device *dev;
+
+	/* get port properties for all ports */
+	for (i = 0; i < adapter->num_ports; i++) {
+
+		if (adapter->port[i])
+			continue;	/* port already up and running */
+
+		/* allocate memory for the port structures */
+		dev = alloc_etherdev(sizeof(struct ehea_port));
+
+		if (!dev) {
+			ehea_error("no mem for net_device");
+			break;
+		}
+
+		port = netdev_priv(dev);
+		port->adapter = adapter;
+		port->netdev = dev;
+		adapter->port[i] = port;
+		port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+		dn = of_find_node_by_name(dn, "ethernet");
+		ret = ehea_setup_single_port(port, dn);
+		if (ret) {
+			/* Free mem for this port struct. the others will be
+			   processed on rollback */
+			free_netdev(dev);
+			adapter->port[i] = NULL;
+			ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
+		}
+	}
+
+	of_node_put(dn);
+
+	/* Check for succesfully set up ports */
+	for (i = 0; i < adapter->num_ports; i++)
+		if (adapter->port[i])
+			port_setup_ok++;
+
+	if (port_setup_ok > 0)
+		ret = 0;	/* At least some ports are setup correctly */
+
+	return ret;
+}
+
+static int __devinit ehea_probe(struct ibmebus_dev *dev,
+				const struct of_device_id *id)
+{
+	int ret = -EINVAL;
+	struct ehea_adapter *adapter = NULL;
+	u64 *adapter_handle = NULL;
+
+	adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+
+	if (!adapter) {
+		dev_err(&dev->ofdev.dev, "No mem for ehea_adapter\n");
+		ret = -ENOMEM;
+		goto kzalloc_adapter_failed;
+	}
+
+
+	adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
+					    NULL);
+
+	if (!adapter_handle) {
+		dev_err(&dev->ofdev.dev, "Failed getting handle for adapter"
+			" '%s'\n", dev->ofdev.node->full_name);
+		ret = -ENODEV;
+		goto get_property_failed;
+	}
+
+	adapter->handle = *adapter_handle;
+	adapter->pd = EHEA_PD_ID;
+
+	dev->ofdev.dev.driver_data = adapter;
+
+	ret = ehea_reg_mr_adapter(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "register Memory Region failed\n");
+		goto register_mr_failed;
+	}
+
+	/* initialize adapter and ports */
+	/* get adapter properties */
+	ret = ehea_sense_adapter_attr(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
+		goto sense_adapter_failed;
+	}
+	dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
+
+	adapter->neq = ehea_create_eq(adapter,
+				      EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
+	if (!adapter->neq) {
+		dev_err(&dev->ofdev.dev, "NEQ creation failed");
+		goto create_neq_failed;
+	}
+
+	tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
+		     (unsigned long)adapter);
+
+	ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
+				ehea_interrupt_neq, SA_INTERRUPT, "ehea_neq",
+				(void*)adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
+		goto request_irq_failed;
+	}
+
+	ret = ehea_setup_ports(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "setup_ports failed");
+		goto setup_ports_failed;
+	}
+
+	ret = 0;
+	goto done;
+
+setup_ports_failed:
+request_irq_failed:
+	ehea_destroy_eq(adapter->neq);
+create_neq_failed:
+sense_adapter_failed:
+	ehea_dereg_mr_adapter(adapter);
+register_mr_failed:
+get_property_failed:
+	kfree(adapter);
+kzalloc_adapter_failed:
+done:
+	return ret;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+	unregister_netdev(port->netdev);
+	kfree(port->mc_list);
+	free_netdev(port->netdev);
+}
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev)
+{
+	int ret = -EINVAL;
+	struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
+	int i;
+
+	for (i = 0; i < adapter->num_ports; i++)
+		if(adapter->port[i]) {
+			ehea_shutdown_single_port(adapter->port[i]);
+			adapter->port[i] = NULL;
+		}
+
+	ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+
+	ehea_destroy_eq(adapter->neq);
+
+	ret = ehea_dereg_mr_adapter(adapter);
+	if (ret) {
+		dev_err(&dev->ofdev.dev, "dereg_mr_adapter failed");
+		goto deregister_mr_failed;
+	}
+	kfree(adapter);
+	ret = 0;
+
+deregister_mr_failed:
+	return ret;
+}
+
+static struct of_device_id ehea_device_table[] = {
+	{
+	 .name = "lhea",
+	 .compatible = "IBM,lhea",
+	 },
+	{},
+};
+
+static struct ibmebus_driver ehea_driver = {
+	.name = "ehea",
+	.id_table = ehea_device_table,
+	.probe = ehea_probe,
+	.remove = ehea_remove,
+};
+
+int __init ehea_module_init(void)
+{
+	int ret = -EINVAL;
+
+	printk("IBM eHEA Ethernet Device Driver (Release %s)\n", DRV_VERSION);
+
+	ret = ibmebus_register_driver(&ehea_driver);
+	if (ret) {
+		ehea_error("failed registering eHEA device driver on ebus");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __exit ehea_module_exit(void)
+{
+	ibmebus_unregister_driver(&ehea_driver);
+}
+
+module_init(ehea_module_init);
+module_exit(ehea_module_exit);

^ permalink raw reply

* [2.6.19 PATCH 0/7] ehea: IBM eHEA Ethernet Device Driver
From: Jan-Bernd Themann @ 2006-08-18 11:28 UTC (permalink / raw)
  To: netdev
  Cc: Thomas Klein, Jan-Bernd Themann, linux-kernel, Thomas Klein,
	linux-ppc, Christoph Raisch, Marcus Eder

Hello,

this is the latest version of the IBM eHEA Ethernet Device Driver.
The main difference to the previous version is the rework of the debug
mechanism. 
We highly appreciate further comments.

Thanks,
Jan-Bernd

Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
Changelog-by:  Jan-Bernd Themann <themann@de.ibm.com>

Differences to patch set: http://www.spinics.net/lists/netdev/msg11593.html

Changelog:

- Logging rework (EDEB macros removed, netif_msg_X mechansim used)


 drivers/net/Kconfig             |    6 
 drivers/net/Makefile            |    1 
 drivers/net/ehea/Makefile       |    7 
 drivers/net/ehea/ehea.h         |  442 +++++++
 drivers/net/ehea/ehea_ethtool.c |  264 ++++
 drivers/net/ehea/ehea_hcall.h   |   51 
 drivers/net/ehea/ehea_hw.h      |  292 ++++
 drivers/net/ehea/ehea_main.c    | 2480 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/ehea/ehea_phyp.c    |  884 ++++++++++++++
 drivers/net/ehea/ehea_phyp.h    |  523 ++++++++
 drivers/net/ehea/ehea_qmr.c     |  643 ++++++++++
 drivers/net/ehea/ehea_qmr.h     |  367 +++++
 12 files changed, 5960 insertions(+)

^ permalink raw reply

* Re: Broken Firewire 400/SCSI on ppc Powerbook5,8
From: Wolfgang Pfeiffer @ 2006-08-18 10:17 UTC (permalink / raw)
  To: Bill Fink; +Cc: linuxppc-dev, linux1394-devel, stefanr
In-Reply-To: <20060818012824.22e70b0f.billfink@mindspring.com>

Hi Bill

Thanks for responding

On Fri, Aug 18, 2006 at 01:28:24AM -0400, Bill Fink wrote:
> Hi Wolfgang,
> 
> On Fri, 18 Aug 2006, Wolfgang Pfeiffer wrote:
> 
> [ ... ]
> > First I load the drivers with this little script:
> > 
> > ------------------------------------------
> > #!/bin/sh -x
> > /bin/sh -n /home/shorty/scripts/scsi.start.sh && \
> > 
> > modprobe raw1394 && \
> > modprobe ieee1394 disable_irm=0 disable_nodemgr=1 && \
> > modprobe ohci1394 && \
> > modprobe eth1394 && \
> > modprobe sbp2 max_speed=3 workarounds=0x1 serialize_io=0 && \
> > sleep 4 && \
> > chown root.shorty /dev/raw1394
> > -------------------------------------------
> 
> I don't know if it matters for you (haven't tried Firewire yet on
> a PowerBook), but on my desktop PowerMac systems, I need a "sleep 2"
> before the modprobe for sbp2, to get my Firewire disks to work
> properly.


No, that doesn't help: I made several changes to the script now, with a
shorter or longer sleep delay, changing driver options - still no /dev/sdX/:


-------------------------------------
#!/bin/sh -x
/bin/sh -n /home/shorty/scripts/scsi.start.sh ; \

modprobe raw1394; \
modprobe ieee1394 disable_irm=1 disable_nodemgr=0; \
modprobe ohci1394; \
modprobe eth1394; \
sleep 4; \
#modprobe sbp2 max_speed=3 workarounds=0x1 serialize_io=0; \
#modprobe sbp2 max_speed=3 serialize_io=0; \
modprobe sbp2; \
sleep 4; \
chown root.shorty /dev/raw1394


--------------------------------------

What I got today is this:

-----------------------------
Aug 18 11:57:46 debby1-6 kernel: [ 2113.770420] ieee1394: Initialized config rom entry `ip1394'
Aug 18 11:57:46 debby1-6 kernel: [ 2113.777915] ieee1394: raw1394: /dev/raw1394 device initialized
Aug 18 11:57:46 debby1-6 kernel: [ 2113.848894] PM: Adding info for ieee1394:fw-host0
Aug 18 11:57:46 debby1-6 kernel: [ 2113.901455] ohci1394: fw-host0: OHCI-1394 1.0 (PCI): IRQ=[40]  MMIO=[f5000000-f50007ff]  Max Packet=[4096]  IR/IT contexts=[8/8]
Aug 18 11:57:46 debby1-6 kernel: [ 2113.961215] eth1394: eth1: IEEE-1394 IPv4 over 1394 Ethernet (fw-host0)
Aug 18 11:57:47 debby1-6 kernel: [ 2115.219661] ieee1394: The root node is not cycle master capable; selecting a new root node and resetting...
Aug 18 11:57:48 debby1-6 kernel: [ 2116.448637] ieee1394: Error parsing configrom for node 0-00:1023
Aug 18 11:57:48 debby1-6 kernel: [ 2116.449037] PM: Adding info for ieee1394:001451fffe3148be
Aug 18 11:57:48 debby1-6 kernel: [ 2116.449126] ieee1394: Host added: ID:BUS[0-02:1023]  GUID[001451fffe3148be]
Aug 18 11:57:48 debby1-6 kernel: [ 2116.449281] PM: Adding info for ieee1394:001451fffe3148be-0
Aug 18 11:57:50 debby1-6 kernel: [ 2118.041601] ieee1394: sbp2: Driver forced to serialize I/O (serialize_io=1)
Aug 18 11:57:50 debby1-6 kernel: [ 2118.041634] ieee1394: sbp2: Try serialize_io=0 for better performance
-----------------------------------

Following a log excerpt from a few days ago, when I got /dev/sda at
least, tho still no disk partition (Please don't ask me how I got that
far: that time I must have played around with the FW drivers, un- and
reloading them again .... and at one moment I had at least the following ):

--------------------------------
Aug 11 23:53:16 debby1-6 kernel: [11154.413116] ieee1394: Node changed: 0-02:102
3 -> 0-00:1023
Aug 11 23:53:21 debby1-6 kernel: [11160.079353] PM: Adding info for ieee1394:003
0ffa046010cd5
Aug 11 23:53:21 debby1-6 kernel: [11160.079456] ieee1394: Node added: ID:BUS[0-0
0:1023]  GUID[0030ffa046010cd5]
Aug 11 23:53:21 debby1-6 kernel: [11160.079626] ieee1394: Node changed: 0-00:102
3 -> 0-02:1023
Aug 11 23:53:21 debby1-6 kernel: [11160.081535] PM: Adding info for ieee1394:003
0ffa046010cd5-0
Aug 11 23:53:21 debby1-6 kernel: [11160.190054] ieee1394: sbp2: Driver forced to
 serialize I/O (serialize_io=1)
Aug 11 23:53:21 debby1-6 kernel: [11160.190070] ieee1394: sbp2: Try serialize_io
=0 for better performance
Aug 11 23:53:21 debby1-6 kernel: [11160.191555] scsi2 : SBP-2 IEEE-1394
Aug 11 23:53:21 debby1-6 kernel: [11160.191815] PM: Adding info for No Bus:host2
Aug 11 23:53:23 debby1-6 kernel: [11161.295090] ieee1394: sbp2: Logged into SBP-
2 device
Aug 11 23:53:23 debby1-6 kernel: [11161.295728] ieee1394: Node 0-00:1023: Max sp
eed [S400] - Max payload [2048]
Aug 11 23:53:23 debby1-6 kernel: [11161.295932] PM: Adding info for No Bus:targe
t2:0:0
Aug 11 23:53:23 debby1-6 kernel: [11161.301996]   Vendor: LSILogic  Model: SYM13
FW500-Disk   Rev: 1.00
Aug 11 23:53:23 debby1-6 kernel: [11161.302026]   Type:   Direct-Access
             ANSI SCSI revision: 00
Aug 11 23:53:23 debby1-6 kernel: [11161.302323] PM: Adding info for scsi:2:0:0:0
Aug 11 23:53:26 debby1-6 udevd-event[5667]: wait_for_sysfs: waiting for '/sys/de
vices/pci0002:24/0002:24:0e.0/fw-host0/0030ffa046010cd5/0030ffa046010cd5-0/host2
/target2:0:0/2:0:0:0/ioerr_cnt' failed
Aug 11 23:53:53 debby1-6 kernel: [11191.302896] ieee1394: sbp2: aborting sbp2 command
Aug 11 23:53:53 debby1-6 kernel: [11191.302912] sd 2:0:0:0:
Aug 11 23:53:53 debby1-6 kernel: [11191.302915]         command: Test Unit Ready: 00 00 00 00 00 00
Aug 11 23:54:03 debby1-6 kernel: [11201.302892] ieee1394: sbp2: aborting sbp2 command
Aug 11 23:54:03 debby1-6 kernel: [11201.302909] sd 2:0:0:0:
Aug 11 23:54:03 debby1-6 kernel: [11201.302913]         command: Test Unit Ready: 00 00 00 00 00 00
Aug 11 23:54:03 debby1-6 kernel: [11201.302957] ieee1394: sbp2: reset requested
Aug 11 23:54:03 debby1-6 kernel: [11201.302962] ieee1394: sbp2: Generating sbp2 fetch agent reset
Aug 11 23:54:13 debby1-6 kernel: [11211.302892] ieee1394: sbp2: aborting sbp2 command
Aug 11 23:54:13 debby1-6 kernel: [11211.302907] sd 2:0:0:0:
Aug 11 23:54:13 debby1-6 kernel: [11211.302910]         command: Test Unit Ready: 00 00 00 00 00 00
Aug 11 23:54:13 debby1-6 kernel: [11211.302955] sd 2:0:0:0: scsi: Device offlined - not ready after error recovery
Aug 11 23:54:13 debby1-6 kernel: [11211.303150] sd 2:0:0:0: rejecting I/O to offline device
Aug 11 23:54:13 debby1-6 kernel: [11211.303199] sd 2:0:0:0: rejecting I/O to offline device
Aug 11 23:54:13 debby1-6 kernel: [11211.303237] sd 2:0:0:0: rejecting I/O to offline device
Aug 11 23:54:13 debby1-6 kernel: [11211.303272] sda : READ CAPACITY failed.
Aug 11 23:54:13 debby1-6 kernel: [11211.303276] sda : status=0, message=00, host=1, driver=00
Aug 11 23:54:13 debby1-6 kernel: [11211.303282] sda : sense not available.
Aug 11 23:54:13 debby1-6 kernel: [11211.303349] sd 2:0:0:0: rejecting I/O to offline device
Aug 11 23:54:13 debby1-6 kernel: [11211.303384] sda: Write Protect is off
Aug 11 23:54:13 debby1-6 kernel: [11211.303390] sda: Mode Sense: 00 00 00 00
Aug 11 23:54:13 debby1-6 kernel: [11211.303423] sd 2:0:0:0: rejecting I/O to offline device
Aug 11 23:54:13 debby1-6 kernel: [11211.303432] sda: asking for cache data failed
Aug 11 23:54:13 debby1-6 kernel: [11211.303436] sda: assuming drive cache: write through
Aug 11 23:54:13 debby1-6 kernel: [11211.304555] sd 2:0:0:0: Attached scsi disk sda
Aug 11 23:54:13 debby1-6 kernel: [11211.304657] sd 2:0:0:0: Attached scsi generic sg0 type 0
-----------------------------


Thanks again, and
Best Regards
Wolfgang


-- 
Wolfgang Pfeiffer: /ICQ: 286585973/ + + +  /AIM: crashinglinux/
http://profiles.yahoo.com/wolfgangpfeiffer

Key ID: E3037113
http://keyserver.mine.nu/pks/lookup?search=0xE3037113&fingerprint=on

^ permalink raw reply

* RE: USB-Driver for Freescale ehci-fsl.c on Kernel 2.6.17
From: Li Yang-r58472 @ 2006-08-18  8:41 UTC (permalink / raw)
  To: Claus Gindhart, linuxppc-embedded
In-Reply-To: <DADA32856852FC458E0F96B664A6F55E011E23F8@kom-mailsrv1.kontron-modular.com>

ehci-fsl.c is included in ehci.c, not handled by Makefile.

Best Regards,
Leo
> -----Original Message-----
> From: linuxppc-embedded-bounces+leoli=3Dfreescale.com@ozlabs.org
> [mailto:linuxppc-embedded-bounces+leoli=3Dfreescale.com@ozlabs.org] On
Behalf Of
> Claus Gindhart
> Sent: Friday, August 18, 2006 2:26 PM
> To: linuxppc-embedded@ozlabs.org
> Subject: USB-Driver for Freescale ehci-fsl.c on Kernel 2.6.17
>=20
> Hi,
>=20
> currently i am migrating an existing Linux-BSP for the MPC8347/9 from
Kernel 2.6.13
> to 2.6.17 with flattened device tree.
>=20
> Now, i recognized, that the Makefile and Kconfig in drivers/usb/host
do not have
> any entries to configure and compile the ehci-fsl.c driver.
>=20
> Does this mean, that ehci-fsl.c is no longer required, because the
generic
> EHCI-driver now handles this; or is it just the case, that USB for
Freescale
> processor was not yet tested on Kernel 2.6.17 ?
>=20
> --
> Mit freundlichen Gruessen / Best regards
>=20
> Claus Gindhart
> SW R&D
> Kontron Modular Computers
> phone :++49 (0)8341-803-374
> mailto:claus.gindhart@kontron-modular.com
> http://www.kontron.com
>=20
> -----BEGIN GEEK CODE BLOCK-----
>   Version: 3.1
>   GU d- s++:>++:+ a+ C++$ !U !P L++>$ E-- W+(-) N- o?
>   K? w !O !M V !PS PE- Y+ PGP+ t 5? X R* tv- b+ DI+++
>   D-- G e++> h--- !r x+++
> ------END GEEK CODE BLOCK------
>=20
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded

^ permalink raw reply

* [RFC/PATCH 4/4] Enable MSI on Powerpc
From: Michael Ellerman @ 2006-08-18  8:13 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Allow PCI_MSI to build on POWERPC.

Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 drivers/pci/Kconfig |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: git/drivers/pci/Kconfig
===================================================================
--- git.orig/drivers/pci/Kconfig
+++ git/drivers/pci/Kconfig
@@ -4,7 +4,7 @@
 config PCI_MSI
 	bool "Message Signaled Interrupts (MSI and MSI-X)"
 	depends on PCI
-	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
+	depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || POWERPC
 	help
 	   This allows device drivers to enable MSI (Message Signaled
 	   Interrupts).  Message Signaled Interrupts enable a device to

^ permalink raw reply

* [RFC/PATCH 3/4] Powerpc MSI support via RTAS
From: Michael Ellerman @ 2006-08-18  8:13 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

Powerpc MSI support via RTAS. Based on Jake's code, reworked to:
 * only ever set 1 MSI.
 * implement disable, we can't do without it.
 * bork if firmware enables MSI-X on us, that's not ok.
 * more error handling.

NOT tested. Mainline apparently isn't booting atm on the machines that
have the required firmware :/

Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---

 arch/powerpc/platforms/pseries/setup.c |    1 
 drivers/pci/Makefile                   |    1 
 drivers/pci/msi-rtas.c                 |  199 +++++++++++++++++++++++++++++++++
 include/asm-powerpc/pci-bridge.h       |    3 
 include/asm-powerpc/rtas.h             |    6 
 5 files changed, 210 insertions(+)

Index: git/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- git.orig/arch/powerpc/platforms/pseries/setup.c
+++ git/arch/powerpc/platforms/pseries/setup.c
@@ -273,6 +273,7 @@ static void __init pseries_discover_pic(
 			return;
 		} else if (strstr(typep, "ppc-xicp")) {
 			ppc_md.init_IRQ       = xics_init_IRQ;
+			rtas_msi_init();
 #ifdef CONFIG_KEXEC
 			ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics;
 #endif
Index: git/drivers/pci/Makefile
===================================================================
--- git.orig/drivers/pci/Makefile
+++ git/drivers/pci/Makefile
@@ -31,6 +31,7 @@ msiobj-$(CONFIG_X86) := msi.o msi-apic.o
 msiobj-$(CONFIG_IA64) := msi.o msi-apic.o
 msiobj-$(CONFIG_IA64_GENERIC) := msi-altix.o
 msiobj-$(CONFIG_IA64_SGI_SN2) := msi-altix.o
+msiobj-$(CONFIG_PPC_PSERIES) := msi-rtas.o
 
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
Index: git/drivers/pci/msi-rtas.c
===================================================================
--- /dev/null
+++ git/drivers/pci/msi-rtas.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright (C) 2006 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ */
+
+#define DEBUG 1
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_MSI_FN	0
+#define RTAS_CHANGE_MSI_FN	1
+#define RTAS_RESET_MSI_FN	2
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 function, u32 num_irqs)
+{
+	u32 addr, seq_num, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	seq_num = 1;
+	do {
+		rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+				BUID_HI(buid), BUID_LO(buid),
+				function, num_irqs, seq_num);
+
+		seq_num = rtas_ret[1];
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "Error[%d]: getting the number of"
+			" MSI interrupts for %s\n", rc, pci_name(pdn->pcidev));
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+	u32 addr, rtas_ret[2];
+	unsigned long buid;
+	int rc;
+
+	addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+	buid = pdn->phb->buid;
+
+	do {
+		rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+			       BUID_HI(buid), BUID_LO(buid), offset);
+	} while (rtas_busy_delay(rc));
+
+	if (rc) {
+		printk(KERN_WARNING "Error[%d]: Querying irq source number "
+				"for %s\n", rc, pci_name(pdn->pcidev));
+		return rc;
+	}
+
+	return rtas_ret[0];
+}
+
+static int msi_enabled(struct pci_dev *pdev)
+{
+	int pos;
+	u16 reg;
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+	if (!pos)
+		return 0;
+
+	pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &reg);
+	if (reg & PCI_MSI_FLAGS_ENABLE)
+		return 1;
+
+	return 0;
+}
+
+static void rtas_disable_msi(struct pci_dev* pdev)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		pr_debug("rtas_disable_msi: No OF device node for %s\n",
+				pci_name(pdev));
+		return;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		pr_debug("rtas_disable_msi: No PCI DN for %s\n",
+				pci_name(pdev));
+		return;
+	}
+
+	/* XXX can we do anything sane if this fails? */
+	rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 0);
+
+	pdev->irq = pdn->saved_irq;
+}
+
+static int rtas_enable_msi(struct pci_dev *pdev)
+{
+	struct device_node *dn;
+	struct pci_dn *pdn;
+	int rc, virq;
+
+	dn = pci_device_to_OF_node(pdev);
+	if (!dn) {
+		pr_debug("rtas_enable_msi: No OF device node for %s\n",
+				pci_name(pdev));
+		goto out_err;
+	}
+
+	if (!of_find_property(dn, "ibm,req#msi", NULL)) {
+		pr_debug("rtas_enable_msi: No ibm,req#msi for %s\n",
+				pci_name(pdev));
+		goto out_err;
+	}
+
+	pdn = PCI_DN(dn);
+	if (!pdn) {
+		pr_debug("rtas_change_msi: No PCI DN for %s\n", pci_name(pdev));
+		goto out_err;
+	}
+
+	pdn->saved_irq = pdev->irq;
+
+	/*
+	 * Try and configure 1 MSI for the device. This should get us
+	 * either 1 MSI, or an error. In the case of an error it's not
+	 * clear whether the device is left with MSI enabled or disabled,
+	 * so I think we should explicitly disable.
+	 */
+	rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, 1);
+	if (rc != 1)
+		goto out_disable;
+
+	/*
+	 * The spec gives firmware the option to enable either MSI or MSI-X,
+	 * this doesn't wash with the Linux API. For the time beinging, we
+	 * kludge around that by checking ourselves if MSI has been enabled.
+	 */
+	if (!msi_enabled(pdev)) {
+		pr_debug("rtas_enable_msi: MSI not enabled by firmware!\n");
+		goto out_disable;
+	}
+
+	rc = rtas_query_irq_number(pdn, 0);
+	if (rc < 0)
+		goto out_disable;
+
+	virq = irq_create_mapping(NULL, rc);
+	if (virq == NO_IRQ) {
+		pr_debug("rtas_enable_msi: Failed mapping hwirq %d\n", rc);
+		goto out_disable;
+	}
+
+	pdev->irq = virq;
+	return 0;
+
+ out_disable:
+	rtas_disable_msi(pdev);
+ out_err:
+	return -1;
+}
+
+void rtas_msi_init(void)
+{
+	query_token  = rtas_token("ibm,query-interrupt-source-number");
+	change_token = rtas_token("ibm,change-msi");
+
+	if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+			(change_token == RTAS_UNKNOWN_SERVICE)) {
+		pr_debug("rtas_msi_init: Couldn't find RTAS tokens, no "
+				"MSI support available.\n");
+		return;
+	}
+
+	pr_debug("rtas_msi_init: Registering MSI callbacks.\n");
+
+	ppc_md.enable_msi = rtas_enable_msi;
+	ppc_md.disable_msi = rtas_disable_msi;
+}
Index: git/include/asm-powerpc/pci-bridge.h
===================================================================
--- git.orig/include/asm-powerpc/pci-bridge.h
+++ git/include/asm-powerpc/pci-bridge.h
@@ -81,6 +81,9 @@ struct pci_dn {
 	struct	pci_dev *pcidev;	/* back-pointer to the pci device */
 	struct	device_node *node;	/* back-pointer to the device_node */
 	u32	config_space[16];	/* saved PCI config space */
+#ifdef CONFIG_PCI_MSI
+	int	saved_irq;		/* saved LSI for MSI */
+#endif
 };
 
 /* Get the pointer to a device_node's pci_dn */
Index: git/include/asm-powerpc/rtas.h
===================================================================
--- git.orig/include/asm-powerpc/rtas.h
+++ git/include/asm-powerpc/rtas.h
@@ -246,5 +246,11 @@ static inline u32 rtas_config_addr(int b
 			(devfn << 8) | (reg & 0xff);
 }
 
+#ifdef CONFIG_PCI_MSI
+extern void rtas_msi_init(void);
+#else
+static inline void rtas_msi_init(void) { }
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* _POWERPC_RTAS_H */

^ permalink raw reply

* [RFC/PATCH 2/4] Allow for non-Intel MSI implementations
From: Michael Ellerman @ 2006-08-18  8:13 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

From: Jake Moilanen <moilanen@austin.ibm.com>

This allows an architecture to provide its own MSI implementation
instead of msi.c and msi-apic.c.  We will need this on IBM System-p
machines where the hypervisor controls the assignment and setup of
MSIs.  A following patch will provide an MSI implementation for these
machines.

Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
---

 drivers/pci/Makefile |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Index: git/drivers/pci/Makefile
===================================================================
--- git.orig/drivers/pci/Makefile
+++ git/drivers/pci/Makefile
@@ -27,9 +27,11 @@ obj-$(CONFIG_PPC64) += setup-bus.o
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
+msiobj-$(CONFIG_X86) := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64) := msi.o msi-apic.o
+msiobj-$(CONFIG_IA64_GENERIC) := msi-altix.o
+msiobj-$(CONFIG_IA64_SGI_SN2) := msi-altix.o
+
 obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
 
 #

^ permalink raw reply

* [RFC/PATCH 1/4] Add firmware flags for PCIe/MSI
From: Michael Ellerman @ 2006-08-18  8:13 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev

From: Jake Moilanen <moilanen@austin.ibm.com>

Add firmware flags for PCIe/MSI.

Signed-off-by: Jake Moilanen <moilanen@austin.ibm.com>
---

 arch/powerpc/kernel/prom_init.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Index: git/arch/powerpc/kernel/prom_init.c
===================================================================
--- git.orig/arch/powerpc/kernel/prom_init.c
+++ git/arch/powerpc/kernel/prom_init.c
@@ -634,6 +634,12 @@ static void __init early_cmdline_parse(v
 /* ibm,dynamic-reconfiguration-memory property supported */
 #define OV5_DRCONF_MEMORY	0x20
 #define OV5_LARGE_PAGES		0x10	/* large pages supported */
+/* PCIe/MSI support. Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI			0x01	/* PCIe/MSI supported */
+#else
+#define OV5_MSI			0x00
+#endif
 
 /*
  * The architecture vector has an array of PVR mask/value pairs,
@@ -677,7 +683,7 @@ static unsigned char ibm_architecture_ve
 	/* option vector 5: PAPR/OF options */
 	3 - 1,				/* length */
 	0,				/* don't ignore, don't halt */
-	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+	OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */

^ permalink raw reply

* Re: [PATCH] Gunzip call fix for PPC kernel images >4MB
From: Benjamin Heyne @ 2006-08-18  8:10 UTC (permalink / raw)
  To: Tom Rini; +Cc: linuxppc-dev, Paul Mackerras, Milton Miller
In-Reply-To: <20060817050408.GJ3249@smtp.west.cox.net>

And so it came to pass, that on Wed, 16 Aug 2006 22:04:08 -0700
Tom Rini <trini@kernel.crashing.org> wrote as thus:

> On Wed, Aug 16, 2006 at 11:31:37AM +0200, Benjamin Heyne wrote:
> 
> > If Kernel images for PPC grow >4MB inflating of the kernel fails.
> > Increasing the link/load address doesn't help. Problem is 
> > solved by replacing the fixed address of the gunzip() call in
> > misc-embedded.c with CONFIG_BOOT_LOAD.
> 
> The arch/ppc/boot code makes some assumptions such as that 4MB-8MB (except
> on 40x which is end of the wrapper code to 8MB, and BOOT_LOAD defaults
> to 4MB here) is free to use for malloc()'ing for the inflate routine.

Well, I just could find this assumptions hardcoded in misc - Not in misc-embedded.
But I am relatively new to kernel programming, so maybe I have missed something.

But despite of that: Shouldn't it be possible to shift this range without
having to change fixed addresses at several places?

> 
> It also assumes that the vmlinux.gz will live at BOOT_LOAD + a bit, when
> the wrapper is set to kick off linux.

As I understand it, the lowest address at which reasonable data starts is
BOOT_LOAD. The space below is used for inflating, right? At least this
seems to be the case for my target (Virtex, ML300) - Do other targets
behave differently?

> 
> Finally, in arch/ppc/boot/ (for both OF and !OF cases) gunzip looks
> like:
> void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)

Ok - The dstlen parameter just tells zlib_inflate() something about the
available space. If the inflated image grows larger, an error occurs.
Therefore, BOOT_LOAD should be a reasonable border because board data
starts beyond - not before.

> 
> So I see 2 problems here.
> 
> First, there are other calls to gunzip with dstlen hard-coded to 4MB, so
> the problem would still exist.

Well, the other one exists in misc.c - But this one doesn't apply to the
embedded target, right?

> 
> Second, and more complexly we want to make sure that we don't tell
> gunzip that the destination size grows into the area it would also be
> using to malloc buffers, unless someone can (and please do if possible)
> explain that it's really OK to uncompress into our zalloc space (there
> is no zfree so maybe it's going to be OK, but I don't know that the
> algorithm wouldn't try and reuse buffers which would be bad).
> 

Well, as I said I am new to kernel programming - So I don't
know exactly where the malloc space starts. I just assumed it would be 
beyond BOOT_START because it seemed to be reasonable (If you have a kernel
which inflated size is exactly 4MB, inflation should also work...does it?).

Probably I missed something - But I don't really see the problem. Would you
please clarify it a little bit?

Best regards
-- 
Benjamin Heyne

^ permalink raw reply

* RE: [PATCH] Directly reference i8259@4d0 nodes in mpc8641_hpcn.dts.
From: Benjamin Herrenschmidt @ 2006-08-18  7:21 UTC (permalink / raw)
  To: Zhang Wei-r63237; +Cc: linuxppc-dev
In-Reply-To: <2176B872C0407E44887F07CCAA8692930F6005@zch01exm21.fsl.freescale.net>

On Fri, 2006-08-18 at 13:54 +0800, Zhang Wei-r63237 wrote:
> Is it a good idea? Why we can not endure the "linux,phandle = <4d0>" in
> i8259 node? And besides, this node was already referenced by the other
> entries.

Because magic numbers are evil and nice names are better ? :)

> Using "&/soc8641@f8000000/pci@8000/i8259@4d0" or label seems so verbose
> and weird.

^ permalink raw reply

* Re: booting with BootX corrupts memory
From: Olaf Hering @ 2006-08-18  7:01 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, Niels Kristian Bech Jensen
In-Reply-To: <1155873732.5803.16.camel@localhost.localdomain>

On Fri, Aug 18, 2006 at 02:02:12PM +1000, Benjamin Herrenschmidt wrote:
> On Wed, 2006-08-09 at 06:00 +0200, Niels Kristian Bech Jensen wrote:
> >  On Tue, Aug  1, Olaf Hering wrote:
> > 
> > > Booting an old Mac with BootX corrupts memory, the kernel seldom gets
> > > into init. Even the built-in initramfs archive gets corrupted. So far I
> > > havent figured out where the corruption starts. The only data point so
> > > far is that a passed initrd gets overwritten with stuff that looks like
> > > part of the device-tree after the call to free_area_init_node() from
> > > paging_init(). Perhaps the virtual/real address mapping isnt handled
> > > correctly.
> > 
> > > This is broken since at least 2.6.15, 2.6.14 dies very early, 2.6.13 was
> > > still ok.
> > 
> > > Symptoms differ, depending on used .config and wether an initrd is passed.
> > 
> > I think I've been hit by this bug on my beige G3 running Ubuntu Edgy.
> > 
> > When booting with initrd the boot process stops before any kernel output (CONFIG_BOOTX_TEXT is not enabled).
> > Booting without initrd works fine - at least until it cannot find the root filesystem driver. ;-)
> 
> Does this patch helps ?

No, now I dont even get console= output on serial console.

^ permalink raw reply

* USB-Driver for Freescale ehci-fsl.c on Kernel 2.6.17
From: Claus Gindhart @ 2006-08-18  6:25 UTC (permalink / raw)
  To: linuxppc-embedded

Hi,

currently i am migrating an existing Linux-BSP for the MPC8347/9 from =
Kernel 2.6.13 to 2.6.17 with flattened device tree.

Now, i recognized, that the Makefile and Kconfig in drivers/usb/host do =
not have any entries to configure and compile the ehci-fsl.c driver.

Does this mean, that ehci-fsl.c is no longer required, because the =
generic EHCI-driver now handles this; or is it just the case, that USB =
for Freescale processor was not yet tested on Kernel 2.6.17 ?

--=20
Mit freundlichen Gruessen / Best regards

Claus Gindhart
SW R&D
Kontron Modular Computers
phone :++49 (0)8341-803-374
mailto:claus.gindhart@kontron-modular.com
http://www.kontron.com

-----BEGIN GEEK CODE BLOCK-----
  Version: 3.1
  GU d- s++:>++:+ a+ C++$ !U !P L++>$ E-- W+(-) N- o?
  K? w !O !M V !PS PE- Y+ PGP+ t 5? X R* tv- b+ DI+++
  D-- G e++> h--- !r x+++
------END GEEK CODE BLOCK------
=20

^ permalink raw reply

* RE: [PATCH] Directly reference i8259@4d0 nodes in mpc8641_hpcn.dts.
From: Zhang Wei-r63237 @ 2006-08-18  5:54 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Mark A. Greer; +Cc: linuxppc-dev
In-Reply-To: <1155866388.5803.10.camel@localhost.localdomain>

Is it a good idea? Why we can not endure the "linux,phandle =3D <4d0>" =
in
i8259 node? And besides, this node was already referenced by the other
entries.

Using "&/soc8641@f8000000/pci@8000/i8259@4d0" or label seems so verbose
and weird.

> -----Original Message-----
> From: linuxppc-dev-bounces+wei.zhang=3Dfreescale.com@ozlabs.org=20
> [mailto:linuxppc-dev-bounces+wei.zhang=3Dfreescale.com@ozlabs.or
> g] On Behalf Of Benjamin Herrenschmidt
> Sent: Friday, August 18, 2006 10:00 AM
> To: Mark A. Greer
> Cc: linuxppc-dev@ozlabs.org
> Subject: Re: [PATCH] Directly reference i8259@4d0 nodes in=20
> mpc8641_hpcn.dts.
>=20
> On Thu, 2006-08-17 at 17:43 -0700, Mark A. Greer wrote:
> > On Fri, Aug 18, 2006 at 10:09:21AM +1000, Benjamin=20
> Herrenschmidt wrote:
> > > On Thu, 2006-08-17 at 16:20 -0500, Jon Loeliger wrote:
> > > > Rather than using some hand-coded linux,phandle
> > > > node references, use DTC's direct node refs ability
> > > > and let it manage the phandle names instead.
> > >=20
> > > Not 100% sure here but can't we use a label and do &label=20
> rather than
> > > having to copy the full path every time ? Would make=20
> things easier :) If
> > > not, that's probably something to add to dtc...
> >=20
> > Isn't linux,phandle basically the label that you speak of, though?
> > IOW, you may be saying, "No, keep using the linux,phandle".
>=20
> No, more something like
>=20
> pic:
>   <pic_node>
>=20
> and later
>=20
> &pic
>=20
> > Just trying to clarify things although I'm not sure that I=20
> really am...  :)
> >=20
> > Mark
>=20
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>=20

^ permalink raw reply

* Re: Broken Firewire 400/SCSI on ppc Powerbook5,8
From: Bill Fink @ 2006-08-18  5:28 UTC (permalink / raw)
  To: Wolfgang Pfeiffer; +Cc: linuxppc-dev, linux1394-devel, stefanr
In-Reply-To: <20060817230347.GC3440@localhost>

Hi Wolfgang,

On Fri, 18 Aug 2006, Wolfgang Pfeiffer wrote:

> Hi All
> 
> Short version first:
> 
> The SCSI/FW routines seem to work like a charm with a LSILogic Model/
> SYM13FW500-Disk on my old Macintosh titanium-IV laptop, with exactly
> the same relatively fresh git-kernel that does not work on the
> PowerBook5,8.  That is I compiled the kernel on the Apple Powerbook5,8
> and installed it on both machines.
> 
> 
> SCSI/FW didn't work ever on the new PowerBook5,8.
> 
> I'll give you first some error messages for the failing FW disk,
> and at the end of this mail you'll find links to technical
> documentation for the 2 failng machines (Powerbook5,8 and FW board/disk)
> 
> First I load the drivers with this little script:
> 
> ------------------------------------------
> #!/bin/sh -x
> /bin/sh -n /home/shorty/scripts/scsi.start.sh && \
> 
> modprobe raw1394 && \
> modprobe ieee1394 disable_irm=0 disable_nodemgr=1 && \
> modprobe ohci1394 && \
> modprobe eth1394 && \
> modprobe sbp2 max_speed=3 workarounds=0x1 serialize_io=0 && \
> sleep 4 && \
> chown root.shorty /dev/raw1394
> -------------------------------------------

I don't know if it matters for you (haven't tried Firewire yet on
a PowerBook), but on my desktop PowerMac systems, I need a "sleep 2"
before the modprobe for sbp2, to get my Firewire disks to work
properly.

						-Hope this helps

						-Bill

^ permalink raw reply

* Re: booting with BootX corrupts memory
From: Benjamin Herrenschmidt @ 2006-08-18  4:02 UTC (permalink / raw)
  To: Niels Kristian Bech Jensen; +Cc: linuxppc-dev, Olaf Hering
In-Reply-To: <1155096025.3813.6.camel@plutonium.opasia.dk>

On Wed, 2006-08-09 at 06:00 +0200, Niels Kristian Bech Jensen wrote:
>  On Tue, Aug  1, Olaf Hering wrote:
> 
> > Booting an old Mac with BootX corrupts memory, the kernel seldom gets
> > into init. Even the built-in initramfs archive gets corrupted. So far I
> > havent figured out where the corruption starts. The only data point so
> > far is that a passed initrd gets overwritten with stuff that looks like
> > part of the device-tree after the call to free_area_init_node() from
> > paging_init(). Perhaps the virtual/real address mapping isnt handled
> > correctly.
> 
> > This is broken since at least 2.6.15, 2.6.14 dies very early, 2.6.13 was
> > still ok.
> 
> > Symptoms differ, depending on used .config and wether an initrd is passed.
> 
> I think I've been hit by this bug on my beige G3 running Ubuntu Edgy.
> 
> When booting with initrd the boot process stops before any kernel output (CONFIG_BOOTX_TEXT is not enabled).
> Booting without initrd works fine - at least until it cannot find the root filesystem driver. ;-)

Does this patch helps ?

Index: linux-work/arch/powerpc/platforms/powermac/bootx_init.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/powermac/bootx_init.c	2006-08-17 16:16:03.000000000 +1000
+++ linux-work/arch/powerpc/platforms/powermac/bootx_init.c	2006-08-18 14:01:36.000000000 +1000
@@ -411,8 +411,15 @@
 	DBG("End of boot params: %x\n", mem_end);
 	rsvmap[0] = mem_start;
 	rsvmap[1] = mem_end;
-	rsvmap[2] = 0;
-	rsvmap[3] = 0;
+	if (bootx_info->ramDisk) {
+		rsvmap[2] = ((unsigned long)bootx_info) + bootx_info->ramDisk;
+		rsvmap[3] = rsvmap[2] + bootx_info->ramDiskSize;
+		rsvmap[4] = 0;
+		rsvmap[5] = 0;
+	} else {
+		rsvmap[2] = 0;
+		rsvmap[3] = 0;
+	}
 
 	return (unsigned long)hdr;
 }
@@ -543,12 +550,12 @@
 	 */
 	if (bi->version < 5) {
 		space = bi->deviceTreeOffset + bi->deviceTreeSize;
-		if (bi->ramDisk)
+		if (bi->ramDisk >= space)
 			space = bi->ramDisk + bi->ramDiskSize;
 	} else
 		space = bi->totalParamsSize;
 
-	bootx_printf("Total space used by parameters & ramdisk: %x \n", space);
+	bootx_printf("Total space used by parameters & ramdisk: 0x%x \n", space);
 
 	/* New BootX will have flushed all TLBs and enters kernel with
 	 * MMU switched OFF, so this should not be useful anymore.

^ permalink raw reply

* Re: Linuxppc-embedded Digest, Vol 24, Issue 42
From: jimmy liu @ 2006-08-18  3:48 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <mailman.3.1155866402.4331.linuxppc-embedded@ozlabs.org>

The following code works on linux 2.6

__volatile__ unsigned char dummy;
u32 msr;
    
local_irq_disable(); 

    
((cpm2_map_t *)CPM_MAP_ADDR)->im_clkrst.car_rmr = 1;  
 /* Checkstop Reset enable */
    
/* Interrupts and MMU off */
__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
    
msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR);
__asm__ __volatile__ ("mtmsr    %0"::"r" (msr)); 
    
dummy = ((cpm2_map_t
*)CPM_MAP_ADDR)->im_clkrst.res[0];
    
printk("Restart failed.\n");
for (;;);


--- linuxppc-embedded-request@ozlabs.org wrote:

> Send Linuxppc-embedded mailing list submissions to
> 	linuxppc-embedded@ozlabs.org
> 
> To subscribe or unsubscribe via the World Wide Web,
> visit
> 
>
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> or, via email, send a message with subject or body
> 'help' to
> 	linuxppc-embedded-request@ozlabs.org
> 
> You can reach the person managing the list at
> 	linuxppc-embedded-owner@ozlabs.org
> 
> When replying, please edit your Subject line so it
> is more specific
> than "Re: Contents of Linuxppc-embedded digest..."
> 
> 
> Today's Topics:
> 
>    1. RE: reboot on PQ2FADS board. (Liu Dave-r63238)
> 
> 
>
----------------------------------------------------------------------
> 
> Message: 1
> Date: Fri, 18 Aug 2006 09:45:21 +0800
> From: "Liu Dave-r63238" <DaveLiu@freescale.com>
> Subject: RE: reboot on PQ2FADS board.
> To: "Zhimin \(Jimmy\) Liu" <zliu@edgar-online.com>,
> 	<linuxppc-embedded@ozlabs.org>
> Message-ID:
> 
>
<995B09A8299C2C44B59866F6391D26350CDA9C@zch01exm21.fsl.freescale.net>
> Content-Type: text/plain; charset="us-ascii"
> 
> Hi Liu,
>  
> please try this..
>  
>      u32 msr;
>      
>      volatile immap_t *immap = (immap_t *)
> IMAP_ADDR;
>      
>      
>      /* Interrupts and MachineCheck off */
>      __asm__ __volatile__ ("mfmsr    %0":"=r"
> (msr):);
>      
>      msr &= ~(MSR_ME | MSR_EE);
>      __asm__ __volatile__ ("mtmsr    %0"::"r"
> (msr)); 
>      
>      immap->im_clkrst.car_rmr = 1;    /* Checkstop
> Reset enable */
> 
>      immap->resxxx = 0;        /* please find one
> immap illegal address
>                                    access it, trig
> reset */
>      for (;;);
> 
> 
> 
> ________________________________
> 
> 	From:
>
linuxppc-embedded-bounces+daveliu=freescale.com@ozlabs.org
>
[mailto:linuxppc-embedded-bounces+daveliu=freescale.com@ozlabs.org]
> On
> Behalf Of Zhimin (Jimmy) Liu
> 	Sent: Friday, August 18, 2006 1:00 AM
> 	To: linuxppc-embedded@ozlabs.org
> 	Subject: reboot on PQ2FADS board.
> 	
> 	
> 
> 	Did you sovlve the problem? I have same issue for
> the  PQ2FADS
> board. 
> 
> 	jimmy 
> 
> -------------- next part --------------
> An HTML attachment was scrubbed...
> URL:
>
http://ozlabs.org/pipermail/linuxppc-embedded/attachments/20060818/968e753a/attachment.html
> 
> 
> ------------------------------
> 
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
>
https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> 
> End of Linuxppc-embedded Digest, Vol 24, Issue 42
> *************************************************
> 


Jimmy Zhimin Liu
mailto:jimmyzhmliu@yahoo.com
www.edgar-online.com
11200 Rockville Pike, Suite 301
Rockville, MD 20874
(301)287-0339(O)
(202)499-6822(H)

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around 
http://mail.yahoo.com 

^ permalink raw reply

* Please pull powerpc.git 'merge' branch
From: Paul Mackerras @ 2006-08-18  2:10 UTC (permalink / raw)
  To: gregkh, linuxppc-dev

Greg,

Please do:

git pull \
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git merge

to get the following PowerPC updates for 2.6.18.

Thanks,
Paul.

 Documentation/powerpc/booting-without-of.txt |   10 -
 arch/powerpc/Kconfig                         |    7 -
 arch/powerpc/boot/dts/mpc8641_hpcn.dts       |  339 ++++++++++++++++++++++++++
 arch/powerpc/configs/g5_defconfig            |  122 ++++++++-
 arch/powerpc/configs/iseries_defconfig       |   78 +++++-
 arch/powerpc/configs/pseries_defconfig       |   78 +++++-
 arch/powerpc/kernel/Makefile                 |    4 
 arch/powerpc/kernel/cpu_setup_power4.S       |    2 
 arch/powerpc/kernel/crash.c                  |   11 +
 arch/powerpc/kernel/irq.c                    |    2 
 arch/powerpc/kernel/kprobes.c                |    2 
 arch/powerpc/kernel/machine_kexec.c          |   56 ++++
 arch/powerpc/kernel/machine_kexec_64.c       |   57 ----
 arch/powerpc/kernel/rtas.c                   |   21 ++
 arch/powerpc/kernel/traps.c                  |   16 +
 arch/powerpc/platforms/pseries/setup.c       |    2 
 arch/powerpc/platforms/pseries/xics.c        |    6 
 arch/powerpc/sysdev/fsl_soc.c                |   12 +
 include/asm-powerpc/kexec.h                  |    3 
 include/asm-powerpc/rtas.h                   |    1 
 20 files changed, 695 insertions(+), 134 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/mpc8641_hpcn.dts

Ananth N Mavinakayanahalli:
      [POWERPC] kprobes: Fix possible system crash during out-of-line single-stepping

Benjamin Herrenschmidt:
      [POWERPC] Fix irq radix tree remapping typo

David Wilder:
      [POWERPC] Make secondary CPUs call into kdump on reset exception

Haren Myneni:
      [POWERPC] Fix might-sleep warning on removing cpus

Jon Loeliger:
      [POWERPC] Convert to mac-address for ethernet MAC address data.
      [POWERPC] Add MPC8641 HPCN Device Tree Source file.
      [POWERPC] Offer PCI as a CONFIG choice for PPC_86xx.
      [POWERPC] Fix the mpc8641_hpcn.dts file.

Michael Ellerman:
      [POWERPC] Move some kexec logic into machine_kexec.c
      [POWERPC] Make crash.c work on 32-bit and 64-bit

Olof Johansson:
      [POWERPC] powerpc: Clear HID0 attention enable on PPC970 at boot time

Sonny Rao:
      [POWERPC] fix PMU initialization on pseries lpar

Will Schmidt:
      [POWERPC] update {g5,iseries,pseries}_defconfigs

^ permalink raw reply

* Re: [PATCH] Directly reference i8259@4d0 nodes in mpc8641_hpcn.dts.
From: Benjamin Herrenschmidt @ 2006-08-18  1:59 UTC (permalink / raw)
  To: Mark A. Greer; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <20060818004301.GA8734@mag.az.mvista.com>

On Thu, 2006-08-17 at 17:43 -0700, Mark A. Greer wrote:
> On Fri, Aug 18, 2006 at 10:09:21AM +1000, Benjamin Herrenschmidt wrote:
> > On Thu, 2006-08-17 at 16:20 -0500, Jon Loeliger wrote:
> > > Rather than using some hand-coded linux,phandle
> > > node references, use DTC's direct node refs ability
> > > and let it manage the phandle names instead.
> > 
> > Not 100% sure here but can't we use a label and do &label rather than
> > having to copy the full path every time ? Would make things easier :) If
> > not, that's probably something to add to dtc...
> 
> Isn't linux,phandle basically the label that you speak of, though?
> IOW, you may be saying, "No, keep using the linux,phandle".

No, more something like

pic:
  <pic_node>

and later

&pic

> Just trying to clarify things although I'm not sure that I really am...  :)
> 
> Mark

^ permalink raw reply

* RE: reboot on PQ2FADS board.
From: Liu Dave-r63238 @ 2006-08-18  1:45 UTC (permalink / raw)
  To: Zhimin (Jimmy) Liu, linuxppc-embedded
In-Reply-To: <BE82DD0EDDEFDE4CA878520C017D8C6F045BA3CF@eolrexc1.eolcorporate.com>

[-- Attachment #1: Type: text/plain, Size: 965 bytes --]

Hi Liu,
 
please try this..
 
     u32 msr;
     
     volatile immap_t *immap = (immap_t *) IMAP_ADDR;
     
     
     /* Interrupts and MachineCheck off */
     __asm__ __volatile__ ("mfmsr    %0":"=r" (msr):);
     
     msr &= ~(MSR_ME | MSR_EE);
     __asm__ __volatile__ ("mtmsr    %0"::"r" (msr)); 
     
     immap->im_clkrst.car_rmr = 1;    /* Checkstop Reset enable */

     immap->resxxx = 0;        /* please find one immap illegal address
                                   access it, trig reset */
     for (;;);



________________________________

	From: linuxppc-embedded-bounces+daveliu=freescale.com@ozlabs.org
[mailto:linuxppc-embedded-bounces+daveliu=freescale.com@ozlabs.org] On
Behalf Of Zhimin (Jimmy) Liu
	Sent: Friday, August 18, 2006 1:00 AM
	To: linuxppc-embedded@ozlabs.org
	Subject: reboot on PQ2FADS board.
	
	

	Did you sovlve the problem? I have same issue for the  PQ2FADS
board. 

	jimmy 


[-- Attachment #2: Type: text/html, Size: 3257 bytes --]

^ permalink raw reply

* [PATCH] Add 85xx DTS files
From: Andy Fleming @ 2006-08-18  1:26 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev

Added the DTS files for the 8540 ADS, and the 8555/41/48 CDS

Signed-of-by: Andy Fleming <afleming@freescale.com>
---
 arch/powerpc/boot/dts/mpc8540ads.dts |  250 ++++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/mpc8541cds.dts |  244 +++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/mpc8548cds.dts |  287 ++++++++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/mpc8555cds.dts |  244 +++++++++++++++++++++++++++++
 4 files changed, 1025 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
new file mode 100644
index 0000000..88b0ea7
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -0,0 +1,250 @@
+/*
+ * MPC8540 ADS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC8540ADS";
+	compatible = "MPC85xxADS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8540@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <0>;	//  33 MHz, from uboot
+			bus-frequency = <0>;	// 166 MHz
+			clock-frequency = <0>;	// 825 MHz, from uboot
+			32-bit;
+			linux,phandle = <201>;
+			linux,boot-cpu;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;	// 128M at 0x0
+	};
+
+	soc8540@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <40000>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			linux,phandle = <24520>;
+			ethernet-phy@0 {
+				linux,phandle = <2452000>;
+				interrupt-parent = <40000>;
+				interrupts = <35 3>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <2452001>;
+				interrupt-parent = <40000>;
+				interrupts = <35 3>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			interrupts = <d 2 e 2 12 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452000>;
+		};
+
+		ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <25000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			interrupts = <13 2 14 2 18 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+		ethernet@26000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "FEC";
+			compatible = "gianfar";
+			reg = <26000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 02 ];
+			interrupts = <19 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>; 	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+		pci@8000 {
+			linux,phandle = <8000>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x02 */
+				1000 0 0 1 40000 31 1
+				1000 0 0 2 40000 32 1
+				1000 0 0 3 40000 33 1
+				1000 0 0 4 40000 34 1
+
+				/* IDSEL 0x03 */
+				1800 0 0 1 40000 34 1
+				1800 0 0 2 40000 31 1
+				1800 0 0 3 40000 32 1
+				1800 0 0 4 40000 33 1
+
+				/* IDSEL 0x04 */
+				2000 0 0 1 40000 33 1
+				2000 0 0 2 40000 34 1
+				2000 0 0 3 40000 31 1
+				2000 0 0 4 40000 32 1
+
+				/* IDSEL 0x05 */
+				2800 0 0 1 40000 32 1
+				2800 0 0 2 40000 33 1
+				2800 0 0 3 40000 34 1
+				2800 0 0 4 40000 31 1
+
+				/* IDSEL 0x0c */
+				6000 0 0 1 40000 31 1
+				6000 0 0 2 40000 32 1
+				6000 0 0 3 40000 33 1
+				6000 0 0 4 40000 34 1
+
+				/* IDSEL 0x0d */
+				6800 0 0 1 40000 34 1
+				6800 0 0 2 40000 31 1
+				6800 0 0 3 40000 32 1
+				6800 0 0 4 40000 33 1
+
+				/* IDSEL 0x0e */
+				7000 0 0 1 40000 33 1
+				7000 0 0 2 40000 34 1
+				7000 0 0 3 40000 31 1
+				7000 0 0 4 40000 32 1
+
+				/* IDSEL 0x0f */
+				7800 0 0 1 40000 32 1
+				7800 0 0 2 40000 33 1
+				7800 0 0 3 40000 34 1
+				7800 0 0 4 40000 31 1
+
+				/* IDSEL 0x12 */
+				9000 0 0 1 40000 31 1
+				9000 0 0 2 40000 32 1
+				9000 0 0 3 40000 33 1
+				9000 0 0 4 40000 34 1
+
+				/* IDSEL 0x13 */
+				9800 0 0 1 40000 34 1
+				9800 0 0 2 40000 31 1
+				9800 0 0 3 40000 32 1
+				9800 0 0 4 40000 33 1
+
+				/* IDSEL 0x14 */
+				a000 0 0 1 40000 33 1
+				a000 0 0 2 40000 34 1
+				a000 0 0 3 40000 31 1
+				a000 0 0 4 40000 32 1
+
+				/* IDSEL 0x15 */
+				a800 0 0 1 40000 32 1
+				a800 0 0 2 40000 33 1
+				a800 0 0 3 40000 34 1
+				a800 0 0 4 40000 31 1>;
+			interrupt-parent = <40000>;
+			interrupts = <08 3>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 80000000 80000000 0 20000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+		};
+
+		pic@40000 {
+			linux,phandle = <40000>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
new file mode 100644
index 0000000..d526397
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -0,0 +1,244 @@
+/*
+ * MPC8541 CDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC8541CDS";
+	compatible = "MPC85xxCDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8541@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <0>;	//  33 MHz, from uboot
+			bus-frequency = <0>;	// 166 MHz
+			clock-frequency = <0>;	// 825 MHz, from uboot
+			32-bit;
+			linux,phandle = <201>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;	// 128M at 0x0
+	};
+
+	soc8541@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <40000>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			linux,phandle = <24520>;
+			ethernet-phy@0 {
+				linux,phandle = <2452000>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <2452001>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			interrupts = <d 2 e 2 12 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452000>;
+		};
+
+		ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <25000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			interrupts = <13 2 14 2 18 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>; 	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		pci@8000 {
+			linux,phandle = <8000>;
+			interrupt-map-mask = <1f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x10 */
+				08000 0 0 1 40000 30 1
+				08000 0 0 2 40000 31 1
+				08000 0 0 3 40000 32 1
+				08000 0 0 4 40000 33 1
+
+				/* IDSEL 0x11 */
+				08800 0 0 1 40000 30 1
+				08800 0 0 2 40000 31 1
+				08800 0 0 3 40000 32 1
+				08800 0 0 4 40000 33 1
+
+				/* IDSEL 0x12 (Slot 1) */
+				09000 0 0 1 40000 30 1
+				09000 0 0 2 40000 31 1
+				09000 0 0 3 40000 32 1
+				09000 0 0 4 40000 33 1
+
+				/* IDSEL 0x13 (Slot 2) */
+				09800 0 0 1 40000 31 1
+				09800 0 0 2 40000 32 1
+				09800 0 0 3 40000 33 1
+				09800 0 0 4 40000 30 1
+
+				/* IDSEL 0x14 (Slot 3) */
+				0a000 0 0 1 40000 32 1
+				0a000 0 0 2 40000 33 1
+				0a000 0 0 3 40000 30 1
+				0a000 0 0 4 40000 31 1
+
+				/* IDSEL 0x15 (Slot 4) */
+				0a800 0 0 1 40000 33 1
+				0a800 0 0 2 40000 30 1
+				0a800 0 0 3 40000 31 1
+				0a800 0 0 4 40000 32 1
+				
+				/* Bus 1 (Tundra Bridge) */
+				/* IDSEL 0x12 (ISA bridge) */
+				19000 0 0 1 40000 30 1
+				19000 0 0 2 40000 31 1
+				19000 0 0 3 40000 32 1
+				19000 0 0 4 40000 33 1>;
+			interrupt-parent = <40000>;
+			interrupts = <08 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 80000000 80000000 0 20000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+
+			i8259@19000 {
+				clock-frequency = <0>;
+				interrupt-controller;
+				device_type = "interrupt-controller";
+				reg = <19000 0 0 0 1>;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				built-in;
+				compatible = "chrp,iic";
+				big-endian;
+				interrupts = <1>;
+				interrupt-parent = <8000>;
+			};
+		};
+
+		pci@9000 {
+			linux,phandle = <9000>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x15 */
+				a800 0 0 1 40000 3b 1
+				a800 0 0 2 40000 3b 1
+				a800 0 0 3 40000 3b 1
+				a800 0 0 4 40000 3b 1>;
+			interrupt-parent = <40000>;
+			interrupts = <09 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 a0000000 0 20000000
+				  01000000 0 00000000 e3000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <9000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+		};
+
+		pic@40000 {
+			linux,phandle = <40000>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
new file mode 100644
index 0000000..ec1446a
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -0,0 +1,287 @@
+/*
+ * MPC8555 CDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC8548CDS";
+	compatible = "MPC85xxCDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8548@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <0>;	//  33 MHz, from uboot
+			bus-frequency = <0>;	// 166 MHz
+			clock-frequency = <0>;	// 825 MHz, from uboot
+			32-bit;
+			linux,phandle = <201>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;	// 128M at 0x0
+	};
+
+	soc8548@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <40000>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			linux,phandle = <24520>;
+			ethernet-phy@0 {
+				linux,phandle = <2452000>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <2452001>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+
+			ethernet-phy@2 {
+				linux,phandle = <2452002>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <2>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@3 {
+				linux,phandle = <2452003>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <3>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			interrupts = <d 2 e 2 12 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452000>;
+		};
+
+		ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <25000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			interrupts = <13 2 14 2 18 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+		ethernet@26000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <26000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 02 ];
+			interrupts = <f 2 10 2 11 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+/* eTSEC 4 is currently broken
+		ethernet@27000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "eTSEC";
+			compatible = "gianfar";
+			reg = <27000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 03 ];
+			interrupts = <15 2 16 2 17 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+ */
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>; 	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		pci@8000 {
+			linux,phandle = <8000>;
+			interrupt-map-mask = <1f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x10 */
+				08000 0 0 1 40000 30 1
+				08000 0 0 2 40000 31 1
+				08000 0 0 3 40000 32 1
+				08000 0 0 4 40000 33 1
+
+				/* IDSEL 0x11 */
+				08800 0 0 1 40000 30 1
+				08800 0 0 2 40000 31 1
+				08800 0 0 3 40000 32 1
+				08800 0 0 4 40000 33 1
+
+				/* IDSEL 0x12 (Slot 1) */
+				09000 0 0 1 40000 30 1
+				09000 0 0 2 40000 31 1
+				09000 0 0 3 40000 32 1
+				09000 0 0 4 40000 33 1
+
+				/* IDSEL 0x13 (Slot 2) */
+				09800 0 0 1 40000 31 1
+				09800 0 0 2 40000 32 1
+				09800 0 0 3 40000 33 1
+				09800 0 0 4 40000 30 1
+
+				/* IDSEL 0x14 (Slot 3) */
+				0a000 0 0 1 40000 32 1
+				0a000 0 0 2 40000 33 1
+				0a000 0 0 3 40000 30 1
+				0a000 0 0 4 40000 31 1
+
+				/* IDSEL 0x15 (Slot 4) */
+				0a800 0 0 1 40000 33 1
+				0a800 0 0 2 40000 30 1
+				0a800 0 0 3 40000 31 1
+				0a800 0 0 4 40000 32 1
+				
+				/* Bus 1 (Tundra Bridge) */
+				/* IDSEL 0x12 (ISA bridge) */
+				19000 0 0 1 40000 30 1
+				19000 0 0 2 40000 31 1
+				19000 0 0 3 40000 32 1
+				19000 0 0 4 40000 33 1>;
+			interrupt-parent = <40000>;
+			interrupts = <08 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 80000000 80000000 0 20000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+
+			i8259@19000 {
+				clock-frequency = <0>;
+				interrupt-controller;
+				device_type = "interrupt-controller";
+				reg = <19000 0 0 0 1>;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				built-in;
+				compatible = "chrp,iic";
+				big-endian;
+				interrupts = <1>;
+				interrupt-parent = <8000>;
+			};
+		};
+
+		pci@9000 {
+			linux,phandle = <9000>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x15 */
+				a800 0 0 1 40000 3b 1
+				a800 0 0 2 40000 3b 1
+				a800 0 0 3 40000 3b 1
+				a800 0 0 4 40000 3b 1>;
+			interrupt-parent = <40000>;
+			interrupts = <09 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 a0000000 0 20000000
+				  01000000 0 00000000 e3000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <9000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+		};
+
+		pic@40000 {
+			linux,phandle = <40000>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+	};
+};
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
new file mode 100644
index 0000000..71fea14
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -0,0 +1,244 @@
+/*
+ * MPC8555 CDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/ {
+	model = "MPC8555CDS";
+	compatible = "MPC85xxCDS";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8555@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <0>;	//  33 MHz, from uboot
+			bus-frequency = <0>;	// 166 MHz
+			clock-frequency = <0>;	// 825 MHz, from uboot
+			32-bit;
+			linux,phandle = <201>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 08000000>;	// 128M at 0x0
+	};
+
+	soc8555@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00100000>;	// CCSRBAR 1M
+		bus-frequency = <0>;
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <1b 2>;
+			interrupt-parent = <40000>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			compatible = "gianfar";
+			reg = <24520 20>;
+			linux,phandle = <24520>;
+			ethernet-phy@0 {
+				linux,phandle = <2452000>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+			};
+			ethernet-phy@1 {
+				linux,phandle = <2452001>;
+				interrupt-parent = <40000>;
+				interrupts = <35 0>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+			};
+		};
+
+		ethernet@24000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <24000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 00 ];
+			interrupts = <0d 2 0e 2 12 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452000>;
+		};
+
+		ethernet@25000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <25000 1000>;
+			local-mac-address = [ 00 E0 0C 00 73 01 ];
+			interrupts = <13 2 14 2 18 2>;
+			interrupt-parent = <40000>;
+			phy-handle = <2452001>;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>; 	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;	// reg base, size
+			clock-frequency = <0>; 	// should we fill in in uboot?
+			interrupts = <1a 2>;
+			interrupt-parent = <40000>;
+		};
+
+		pci@8000 {
+			linux,phandle = <8000>;
+			interrupt-map-mask = <1f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x10 */
+				08000 0 0 1 40000 30 1
+				08000 0 0 2 40000 31 1
+				08000 0 0 3 40000 32 1
+				08000 0 0 4 40000 33 1
+
+				/* IDSEL 0x11 */
+				08800 0 0 1 40000 30 1
+				08800 0 0 2 40000 31 1
+				08800 0 0 3 40000 32 1
+				08800 0 0 4 40000 33 1
+
+				/* IDSEL 0x12 (Slot 1) */
+				09000 0 0 1 40000 30 1
+				09000 0 0 2 40000 31 1
+				09000 0 0 3 40000 32 1
+				09000 0 0 4 40000 33 1
+
+				/* IDSEL 0x13 (Slot 2) */
+				09800 0 0 1 40000 31 1
+				09800 0 0 2 40000 32 1
+				09800 0 0 3 40000 33 1
+				09800 0 0 4 40000 30 1
+
+				/* IDSEL 0x14 (Slot 3) */
+				0a000 0 0 1 40000 32 1
+				0a000 0 0 2 40000 33 1
+				0a000 0 0 3 40000 30 1
+				0a000 0 0 4 40000 31 1
+
+				/* IDSEL 0x15 (Slot 4) */
+				0a800 0 0 1 40000 33 1
+				0a800 0 0 2 40000 30 1
+				0a800 0 0 3 40000 31 1
+				0a800 0 0 4 40000 32 1
+				
+				/* Bus 1 (Tundra Bridge) */
+				/* IDSEL 0x12 (ISA bridge) */
+				19000 0 0 1 40000 30 1
+				19000 0 0 2 40000 31 1
+				19000 0 0 3 40000 32 1
+				19000 0 0 4 40000 33 1>;
+			interrupt-parent = <40000>;
+			interrupts = <08 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 80000000 80000000 0 20000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+
+			i8259@19000 {
+				clock-frequency = <0>;
+				interrupt-controller;
+				device_type = "interrupt-controller";
+				reg = <19000 0 0 0 1>;
+				#address-cells = <0>;
+				#interrupt-cells = <2>;
+				built-in;
+				compatible = "chrp,iic";
+				big-endian;
+				interrupts = <1>;
+				interrupt-parent = <8000>;
+			};
+		};
+
+		pci@9000 {
+			linux,phandle = <9000>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+				/* IDSEL 0x15 */
+				a800 0 0 1 40000 3b 1
+				a800 0 0 2 40000 3b 1
+				a800 0 0 3 40000 3b 1
+				a800 0 0 4 40000 3b 1>;
+			interrupt-parent = <40000>;
+			interrupts = <09 2>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 a0000000 0 20000000
+				  01000000 0 00000000 e3000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <9000 1000>;
+			compatible = "85xx";
+			device_type = "pci";
+		};
+
+		pic@40000 {
+			linux,phandle = <40000>;
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <40000 40000>;
+			built-in;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+	};
+};
-- 
2006_06_07.01.gittree_pull-dirty

^ permalink raw reply related

* [PATCH] Fix CDS IRQ handling and PCI code
From: Andy Fleming @ 2006-08-18  1:24 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev

* Fix IRQ support in the 85xx CDS boards so it uses the new
  generic stuff
* Fix PCI IRQ mapping to use the device tree
* Disabled i8259 support to allow the CDS to boot.  This will be
  fixed soon, but the current code doesn't even compile, so this
  is a vast improvement

Signed-off-by: Andy Fleming <afleming@freescale.com>
---

This patch *also* really needs to go in for 2.6.18.

Thanks,
Andy

 arch/powerpc/platforms/85xx/Kconfig       |    1 
 arch/powerpc/platforms/85xx/mpc85xx_cds.c |  210 ++++++++++++-----------------
 2 files changed, 88 insertions(+), 123 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 454fc53..c3268d9 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -14,7 +14,6 @@ config MPC8540_ADS
 config MPC85xx_CDS
 	bool "Freescale MPC85xx CDS"
 	select DEFAULT_UIMAGE
-	select PPC_I8259 if PCI
 	help
 	  This option enables support for the MPC85xx CDS board
 
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 5fd53eb..c9c7ffc 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -57,94 +57,8 @@ #endif
 static int cds_pci_slot = 2;
 static volatile u8 *cadmus;
 
-/*
- * Internal interrupts are all Level Sensitive, and Positive Polarity
- *
- * Note:  Likely, this table and the following function should be
- *        obtained and derived from the OF Device Tree.
- */
-static u_char mpc85xx_cds_openpic_initsenses[] __initdata = {
-	MPC85XX_INTERNAL_IRQ_SENSES,
-#if defined(CONFIG_PCI)
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE),	/* Ext 0: PCI slot 0 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 1: PCI slot 1 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 2: PCI slot 2 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 3: PCI slot 3 */
-#else
-	0x0,				/* External  0: */
-	0x0,				/* External  1: */
-	0x0,				/* External  2: */
-	0x0,				/* External  3: */
-#endif
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 5: PHY */
-	0x0,				/* External  6: */
-	0x0,				/* External  7: */
-	0x0,				/* External  8: */
-	0x0,				/* External  9: */
-	0x0,				/* External 10: */
-#ifdef CONFIG_PCI
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),    /* Ext 11: PCI2 slot 0 */
-#else
-	0x0,				/* External 11: */
-#endif
-};
-
 
 #ifdef CONFIG_PCI
-/*
- * interrupt routing
- */
-int
-mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
-
-	if (!hose->index)
-	{
-		/* Handle PCI1 interrupts */
-		char pci_irq_table[][4] =
-			/*
-			 *      PCI IDSEL/INTPIN->INTLINE
-			 *        A      B      C      D
-			 */
-
-			/* Note IRQ assignment for slots is based on which slot the elysium is
-			 * in -- in this setup elysium is in slot #2 (this PIRQA as first
-			 * interrupt on slot */
-		{
-			{ 0, 1, 2, 3 }, /* 16 - PMC */
-			{ 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */
-			{ 0, 1, 2, 3 }, /* 18 - Slot 1 */
-			{ 1, 2, 3, 0 }, /* 19 - Slot 2 */
-			{ 2, 3, 0, 1 }, /* 20 - Slot 3 */
-			{ 3, 0, 1, 2 }, /* 21 - Slot 4 */
-		};
-
-		const long min_idsel = 16, max_idsel = 21, irqs_per_slot = 4;
-		int i, j;
-
-		for (i = 0; i < 6; i++)
-			for (j = 0; j < 4; j++)
-				pci_irq_table[i][j] =
-					((pci_irq_table[i][j] + 5 -
-					  cds_pci_slot) & 0x3) + PIRQ0A;
-
-		return PCI_IRQ_TABLE_LOOKUP;
-	} else {
-		/* Handle PCI2 interrupts (if we have one) */
-		char pci_irq_table[][4] =
-		{
-			/*
-			 * We only have one slot and one interrupt
-			 * going to PIRQA - PIRQD */
-			{ PIRQ1A, PIRQ1A, PIRQ1A, PIRQ1A }, /* 21 - slot 0 */
-		};
-
-		const long min_idsel = 21, max_idsel = 21, irqs_per_slot = 4;
-
-		return PCI_IRQ_TABLE_LOOKUP;
-	}
-}
 
 #define ARCADIA_HOST_BRIDGE_IDSEL	17
 #define ARCADIA_2ND_BRIDGE_IDSEL	3
@@ -210,50 +124,104 @@ mpc85xx_cds_pcibios_fixup(void)
 		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
 		pci_dev_put(dev);
 	}
+
+	/* Now map all the PCI irqs */
+	dev = NULL;
+	for_each_pci_dev(dev)
+		pci_read_irq_line(dev);
+}
+
+#ifdef CONFIG_PPC_I8259
+#warning The i8259 PIC support is currently broken
+static void mpc85xx_8259_cascade(unsigned int irq, struct
+		irq_desc *desc, struct pt_regs *regs)
+{
+	unsigned int cascade_irq = i8259_irq(regs);
+
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq, regs);
+
+	desc->chip->eoi(irq);
 }
+#endif /* PPC_I8259 */
 #endif /* CONFIG_PCI */
 
 void __init mpc85xx_cds_pic_init(void)
 {
-	struct mpic *mpic1;
-	phys_addr_t OpenPIC_PAddr;
+	struct mpic *mpic;
+	struct resource r;
+	struct device_node *np = NULL;
+	struct device_node *cascade_node = NULL;
+	int cascade_irq;
 
-	/* Determine the Physical Address of the OpenPIC regs */
-	OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET;
+	np = of_find_node_by_type(np, "open-pic");
+
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
 
-	mpic1 = mpic_alloc(OpenPIC_PAddr,
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Failed to map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	mpic = mpic_alloc(np, r.start,
 			MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
-			4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250,
-			mpc85xx_cds_openpic_initsenses,
-			sizeof(mpc85xx_cds_openpic_initsenses), " OpenPIC  ");
-	BUG_ON(mpic1 == NULL);
-	mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200);
-	mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280);
-	mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300);
-	mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380);
-	mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400);
-	mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480);
-	mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500);
-	mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580);
-
-	/* dummy mappings to get to 48 */
-	mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600);
-	mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680);
-	mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700);
-	mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780);
-
-	/* External ints */
-	mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000);
-	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
-	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
-
-	mpic_init(mpic1);
+			4, 0, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+	
+	/* Return the mpic node */
+	of_node_put(np);
+
+	mpic_assign_isu(mpic, 0, r.start + 0x10200);
+	mpic_assign_isu(mpic, 1, r.start + 0x10280);
+	mpic_assign_isu(mpic, 2, r.start + 0x10300);
+	mpic_assign_isu(mpic, 3, r.start + 0x10380);
+	mpic_assign_isu(mpic, 4, r.start + 0x10400);
+	mpic_assign_isu(mpic, 5, r.start + 0x10480);
+	mpic_assign_isu(mpic, 6, r.start + 0x10500);
+	mpic_assign_isu(mpic, 7, r.start + 0x10580);
+
+	/* Used only for 8548 so far, but no harm in
+	 * allocating them for everyone */
+	mpic_assign_isu(mpic, 8, r.start + 0x10600);
+	mpic_assign_isu(mpic, 9, r.start + 0x10680);
+	mpic_assign_isu(mpic, 10, r.start + 0x10700);
+	mpic_assign_isu(mpic, 11, r.start + 0x10780);
+
+	/* External Interrupts */
+	mpic_assign_isu(mpic, 12, r.start + 0x10000);
+	mpic_assign_isu(mpic, 13, r.start + 0x10080);
+	mpic_assign_isu(mpic, 14, r.start + 0x10100);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_PPC_I8259
+	/* Initialize the i8259 controller */
+	for_each_node_by_type(np, "interrupt-controller")
+		if (device_is_compatible(np, "chrp,iic")) {
+			cascade_node = np;
+			break;
+		}
+
+	if (cascade_node == NULL) {
+		printk(KERN_DEBUG "Could not find i8259 PIC\n");
+		return;
+	}
 
-#ifdef CONFIG_PCI
-	mpic_setup_cascade(PIRQ0A, i8259_irq_cascade, NULL);
+	cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+	if (cascade_irq == NO_IRQ) {
+		printk(KERN_ERR "Failed to map cascade interrupt\n");
+		return;
+	}
 
-	i8259_init(0,0);
-#endif
+	i8259_init(cascade_node, 0);
+	of_node_put(cascade_node);
+
+	set_irq_chained_handler(cascade_irq, mpc85xx_8259_cascade);
+#endif /* CONFIG_PPC_I8259 */
 }
 
 
@@ -298,8 +266,6 @@ #ifdef CONFIG_PCI
 		add_bridge(np);
 
 	ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup;
-	ppc_md.pci_swizzle = common_swizzle;
-	ppc_md.pci_map_irq = mpc85xx_map_irq;
 	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
 #endif
 
-- 
2006_06_07.01.gittree_pull-dirty

^ permalink raw reply related

* [PATCH] Fix IRQ handling on MPC8540 ADS
From: Andy Fleming @ 2006-08-18  1:22 UTC (permalink / raw)
  To: Paul Mackerras, linuxppc-dev

* Fixed IRQ handling for the 85xx ADS boards so it uses the new
  generic irq stuff
* Fixed PCI IRQ mapping so it comes from the device tree

Signed-off-by: Andy Fleming <afleming@freescale.com>
---

This patch *really* needs to go in before 2.6.18 is final, else 2.6.18 
doesn't build for 85xx.

Thanks,
Andy

 arch/powerpc/platforms/85xx/mpc85xx_ads.c |  162 ++++++++++-------------------
 1 files changed, 55 insertions(+), 107 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index d0cfcdb..6223409 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -37,79 +37,7 @@ unsigned long isa_io_base = 0;
 unsigned long isa_mem_base = 0;
 #endif
 
-/*
- * Internal interrupts are all Level Sensitive, and Positive Polarity
- *
- * Note:  Likely, this table and the following function should be
- *        obtained and derived from the OF Device Tree.
- */
-static u_char mpc85xx_ads_openpic_initsenses[] __initdata = {
-	MPC85XX_INTERNAL_IRQ_SENSES,
-	0x0,			/* External  0: */
-#if defined(CONFIG_PCI)
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 1: PCI slot 0 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 2: PCI slot 1 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 3: PCI slot 2 */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* Ext 4: PCI slot 3 */
-#else
-	0x0,			/* External  1: */
-	0x0,			/* External  2: */
-	0x0,			/* External  3: */
-	0x0,			/* External  4: */
-#endif
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 5: PHY */
-	0x0,			/* External  6: */
-	(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE),	/* External 7: PHY */
-	0x0,			/* External  8: */
-	0x0,			/* External  9: */
-	0x0,			/* External 10: */
-	0x0,			/* External 11: */
-};
-
 #ifdef CONFIG_PCI
-/*
- * interrupt routing
- */
-
-int
-mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
-{
-	static char pci_irq_table[][4] =
-	    /*
-	     * This is little evil, but works around the fact
-	     * that revA boards have IDSEL starting at 18
-	     * and others boards (older) start at 12
-	     *
-	     *      PCI IDSEL/INTPIN->INTLINE
-	     *       A      B      C      D
-	     */
-	{
-		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 2 */
-		{PIRQD, PIRQA, PIRQB, PIRQC},
-		{PIRQC, PIRQD, PIRQA, PIRQB},
-		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 5 */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 12 */
-		{PIRQD, PIRQA, PIRQB, PIRQC},
-		{PIRQC, PIRQD, PIRQA, PIRQB},
-		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 15 */
-		{0, 0, 0, 0},	/* -- */
-		{0, 0, 0, 0},	/* -- */
-		{PIRQA, PIRQB, PIRQC, PIRQD},	/* IDSEL 18 */
-		{PIRQD, PIRQA, PIRQB, PIRQC},
-		{PIRQC, PIRQD, PIRQA, PIRQB},
-		{PIRQB, PIRQC, PIRQD, PIRQA},	/* IDSEL 21 */
-	};
-
-	const long min_idsel = 2, max_idsel = 21, irqs_per_slot = 4;
-	return PCI_IRQ_TABLE_LOOKUP;
-}
-
 int
 mpc85xx_exclude_device(u_char bus, u_char devfn)
 {
@@ -119,44 +47,63 @@ mpc85xx_exclude_device(u_char bus, u_cha
 		return PCIBIOS_SUCCESSFUL;
 }
 
+void __init
+mpc85xx_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev)
+		pci_read_irq_line(dev);
+}
 #endif /* CONFIG_PCI */
 
 
 void __init mpc85xx_ads_pic_init(void)
 {
-	struct mpic *mpic1;
-	phys_addr_t OpenPIC_PAddr;
-
-	/* Determine the Physical Address of the OpenPIC regs */
-	OpenPIC_PAddr = get_immrbase() + MPC85xx_OPENPIC_OFFSET;
-
-	mpic1 = mpic_alloc(OpenPIC_PAddr,
-			   MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
-			   4, MPC85xx_OPENPIC_IRQ_OFFSET, 0, 250,
-			   mpc85xx_ads_openpic_initsenses,
-			   sizeof(mpc85xx_ads_openpic_initsenses),
-			   " OpenPIC  ");
-	BUG_ON(mpic1 == NULL);
-	mpic_assign_isu(mpic1, 0, OpenPIC_PAddr + 0x10200);
-	mpic_assign_isu(mpic1, 1, OpenPIC_PAddr + 0x10280);
-	mpic_assign_isu(mpic1, 2, OpenPIC_PAddr + 0x10300);
-	mpic_assign_isu(mpic1, 3, OpenPIC_PAddr + 0x10380);
-	mpic_assign_isu(mpic1, 4, OpenPIC_PAddr + 0x10400);
-	mpic_assign_isu(mpic1, 5, OpenPIC_PAddr + 0x10480);
-	mpic_assign_isu(mpic1, 6, OpenPIC_PAddr + 0x10500);
-	mpic_assign_isu(mpic1, 7, OpenPIC_PAddr + 0x10580);
-
-	/* dummy mappings to get to 48 */
-	mpic_assign_isu(mpic1, 8, OpenPIC_PAddr + 0x10600);
-	mpic_assign_isu(mpic1, 9, OpenPIC_PAddr + 0x10680);
-	mpic_assign_isu(mpic1, 10, OpenPIC_PAddr + 0x10700);
-	mpic_assign_isu(mpic1, 11, OpenPIC_PAddr + 0x10780);
-
-	/* External ints */
-	mpic_assign_isu(mpic1, 12, OpenPIC_PAddr + 0x10000);
-	mpic_assign_isu(mpic1, 13, OpenPIC_PAddr + 0x10080);
-	mpic_assign_isu(mpic1, 14, OpenPIC_PAddr + 0x10100);
-	mpic_init(mpic1);
+	struct mpic *mpic;
+	struct resource r;
+	struct device_node *np = NULL;
+
+	np = of_find_node_by_type(np, "open-pic");
+
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+
+	if(of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Could not map mpic register space\n");
+		of_put_node(np);
+		return;
+	}
+
+	mpic = mpic_alloc(np, r.start,
+			MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			4, 0, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+	of_put_node(np);
+
+	mpic_assign_isu(mpic, 0, r.start + 0x10200);
+	mpic_assign_isu(mpic, 1, r.start + 0x10280);
+	mpic_assign_isu(mpic, 2, r.start + 0x10300);
+	mpic_assign_isu(mpic, 3, r.start + 0x10380);
+	mpic_assign_isu(mpic, 4, r.start + 0x10400);
+	mpic_assign_isu(mpic, 5, r.start + 0x10480);
+	mpic_assign_isu(mpic, 6, r.start + 0x10500);
+	mpic_assign_isu(mpic, 7, r.start + 0x10580);
+
+	/* Unused on this platform (leave room for 8548) */
+	mpic_assign_isu(mpic, 8, r.start + 0x10600);
+	mpic_assign_isu(mpic, 9, r.start + 0x10680);
+	mpic_assign_isu(mpic, 10, r.start + 0x10700);
+	mpic_assign_isu(mpic, 11, r.start + 0x10780);
+
+	/* External Interrupts */
+	mpic_assign_isu(mpic, 12, r.start + 0x10000);
+	mpic_assign_isu(mpic, 13, r.start + 0x10080);
+	mpic_assign_isu(mpic, 14, r.start + 0x10100);
+
+	mpic_init(mpic);
 }
 
 /*
@@ -165,7 +112,9 @@ void __init mpc85xx_ads_pic_init(void)
 static void __init mpc85xx_ads_setup_arch(void)
 {
 	struct device_node *cpu;
+#ifdef CONFIG_PCI
 	struct device_node *np;
+#endif
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_ads_setup_arch()", 0);
@@ -186,8 +135,7 @@ #ifdef CONFIG_PCI
 	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
 		add_bridge(np);
 
-	ppc_md.pci_swizzle = common_swizzle;
-	ppc_md.pci_map_irq = mpc85xx_map_irq;
+	ppc_md.pcibios_fixup = mpc85xx_pcibios_fixup;
 	ppc_md.pci_exclude_device = mpc85xx_exclude_device;
 #endif
 
-- 
2006_06_07.01.gittree_pull-dirty

^ permalink raw reply related

* Re: [PATCH] Directly reference i8259@4d0 nodes in mpc8641_hpcn.dts.
From: Mark A. Greer @ 2006-08-18  0:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <1155859761.5803.6.camel@localhost.localdomain>

On Fri, Aug 18, 2006 at 10:09:21AM +1000, Benjamin Herrenschmidt wrote:
> On Thu, 2006-08-17 at 16:20 -0500, Jon Loeliger wrote:
> > Rather than using some hand-coded linux,phandle
> > node references, use DTC's direct node refs ability
> > and let it manage the phandle names instead.
> 
> Not 100% sure here but can't we use a label and do &label rather than
> having to copy the full path every time ? Would make things easier :) If
> not, that's probably something to add to dtc...

Isn't linux,phandle basically the label that you speak of, though?
IOW, you may be saying, "No, keep using the linux,phandle".

Just trying to clarify things although I'm not sure that I really am...  :)

Mark

^ permalink raw reply

* Re: update: consolidated flat device tree code
From: Michael Ellerman @ 2006-08-18  0:34 UTC (permalink / raw)
  To: Hollis Blanchard
  Cc: linuxppc-dev, Pantelis Antoniou, Sachin P. Sant,
	linuxppc-embedded
In-Reply-To: <1155860626.27466.126.camel@basalt.austin.ibm.com>

[-- Attachment #1: Type: text/plain, Size: 868 bytes --]

On Thu, 2006-08-17 at 19:23 -0500, Hollis Blanchard wrote:
> Changes:
> - converted some ints to "unsigned", since gcc was generating warnings
> and negative lengths don't make sense in the flat data structure.
> - added ft_set_prop(), which doesn't yet resize properties but will in
> the future.
> - added an explicit copyright statement.
> 
> Still haven't looked to merge Matt's changes (because I'm busy, the
> current code works for me, and they haven't been accepted in u-boot
> yet).
> 
> Current users: Xen
> Future users: Mark's Linux bootwrapper code
> Potential users: kexec, u-boot

.. iSeries bootwrapper code?


-- 
Michael Ellerman
IBM OzLabs

wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)

We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]

^ permalink raw reply

* Re: update: consolidated flat device tree code
From: Hollis Blanchard @ 2006-08-18  0:29 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Pantelis Antoniou, Sachin P. Sant, linuxppc-embedded
In-Reply-To: <1155860626.27466.126.camel@basalt.austin.ibm.com>

On Thu, 2006-08-17 at 19:23 -0500, Hollis Blanchard wrote:
> Changes:
> - converted some ints to "unsigned", since gcc was generating warnings
> and negative lengths don't make sense in the flat data structure.
> - added ft_set_prop(), which doesn't yet resize properties but will in
> the future.
> - added an explicit copyright statement.
> 
> Still haven't looked to merge Matt's changes (because I'm busy, the
> current code works for me, and they haven't been accepted in u-boot
> yet).
> 
> Current users: Xen
> Future users: Mark's Linux bootwrapper code
> Potential users: kexec, u-boot

Forgot to add that dtc itself is a potential user of this code.

-- 
Hollis Blanchard
IBM Linux Technology Center

^ permalink raw reply


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