Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next-2.6 0/2] qlcnic: Driver fixes
From: Anirban Chakraborty @ 2010-06-29 17:51 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org
  Cc: Ameen Rahman, Dept_NX_Linux_NIC_Driver

Resubmitting following two patches. Please apply.

thanks,
Anirban


^ permalink raw reply

* [PATCH net-next-2.6 1/2] qlcnic: Remove obsolete code
From: Anirban Chakraborty @ 2010-06-29 17:52 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org
  Cc: Dept_NX_Linux_NIC_Driver, Ameen Rahman


Current driver uses FW API version 2 and thus code corresponding to FW API
version 1 has become obsolete. Clean up this from the driver.

Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic_ctx.c  |   26 ++++----------------------
 drivers/net/qlcnic/qlcnic_hdr.h  |    6 ------
 drivers/net/qlcnic/qlcnic_init.c |   16 +++++++---------
 drivers/net/qlcnic/qlcnic_main.c |   22 ++--------------------
 4 files changed, 13 insertions(+), 57 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 941cd08..7969a7a 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -224,12 +224,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 		rds_ring = &recv_ctx->rds_rings[i];
 
 		reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
-		if (adapter->fw_hal_version == QLCNIC_FW_BASE)
-			rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg - 0x200));
-		else
-			rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 +
-				reg;
+		rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 + reg;
 	}
 
 	prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -241,16 +236,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
 		reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
 		reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
 
-		if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
-			sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg - 0x200));
-			sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(reg2 - 0x200));
-		} else {
-			sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 +
-				reg;
-			sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
-		}
+		sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg;
+		sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
 	}
 
 	recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -352,12 +339,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
 
 	if (err == QLCNIC_RCODE_SUCCESS) {
 		temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
-		if (adapter->fw_hal_version == QLCNIC_FW_BASE)
-			tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
-				QLCNIC_REG(temp - 0x200));
-		else
-			tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 +
-				temp;
+		tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 + temp;
 
 		adapter->tx_context_id =
 			le16_to_cpu(prsp->context_id);
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index 7b81cab..15fc320 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -778,12 +778,6 @@ enum {
 	QLCNIC_NON_PRIV_FUNC	= 2
 };
 
-/* FW HAL api version */
-enum {
-	QLCNIC_FW_BASE	= 1,
-	QLCNIC_FW_NPAR	= 2
-};
-
 #define QLC_DEV_DRV_DEFAULT 0x11111111
 
 #define LSB(x)	((uint8_t)(x))
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 6678127..75ba744 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -548,16 +548,14 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
 	int timeo;
 	u32 val;
 
-	if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
-		val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
-		val = QLC_DEV_GET_DRV(val, adapter->portnum);
-		if ((val & 0x3) != QLCNIC_TYPE_NIC) {
-			dev_err(&adapter->pdev->dev,
-				"Not an Ethernet NIC func=%u\n", val);
-			return -EIO;
-		}
-		adapter->physical_port = (val >> 2);
+	val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+	val = QLC_DEV_GET_DRV(val, adapter->portnum);
+	if ((val & 0x3) != QLCNIC_TYPE_NIC) {
+		dev_err(&adapter->pdev->dev,
+			"Not an Ethernet NIC func=%u\n", val);
+		return -EIO;
 	}
+	adapter->physical_port = (val >> 2);
 	if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
 		timeo = 30;
 
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 3b71dfc..981aa91 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -377,15 +377,6 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 };
 
 static struct qlcnic_nic_template qlcnic_ops = {
-	.get_mac_addr = qlcnic_get_mac_addr,
-	.config_bridged_mode = qlcnic_config_bridged_mode,
-	.config_led = qlcnic_config_led,
-	.set_ilb_mode = qlcnic_set_ilb_mode,
-	.clear_ilb_mode = qlcnic_clear_ilb_mode,
-	.start_firmware = qlcnic_start_firmware
-};
-
-static struct qlcnic_nic_template qlcnic_pf_ops = {
 	.get_mac_addr = qlcnic_get_mac_address,
 	.config_bridged_mode = qlcnic_config_bridged_mode,
 	.config_led = qlcnic_config_led,
@@ -534,15 +525,6 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 
 	/* Determine FW API version */
 	adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
-	if (adapter->fw_hal_version == ~0) {
-		adapter->nic_ops = &qlcnic_ops;
-		adapter->fw_hal_version = QLCNIC_FW_BASE;
-		adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn);
-		adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
-		dev_info(&adapter->pdev->dev,
-			"FW does not support nic partion\n");
-		return adapter->fw_hal_version;
-	}
 
 	/* Find PCI function number */
 	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
@@ -569,7 +551,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 	switch (priv_level) {
 	case QLCNIC_MGMT_FUNC:
 		adapter->op_mode = QLCNIC_MGMT_FUNC;
-		adapter->nic_ops = &qlcnic_pf_ops;
+		adapter->nic_ops = &qlcnic_ops;
 		qlcnic_get_pci_info(adapter);
 		/* Set privilege level for other functions */
 		qlcnic_set_function_modes(adapter);
@@ -582,7 +564,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 		dev_info(&adapter->pdev->dev,
 			"HAL Version: %d, Privileged function\n",
 			adapter->fw_hal_version);
-		adapter->nic_ops = &qlcnic_pf_ops;
+		adapter->nic_ops = &qlcnic_ops;
 		break;
 	case QLCNIC_NON_PRIV_FUNC:
 		adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
-- 
1.7.1


^ permalink raw reply related

* [PATCH net-next-2.6 2/2] qlcnic: Add support for configuring eswitch and npars
From: Anirban Chakraborty @ 2010-06-29 17:52 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org
  Cc: Dept_NX_Linux_NIC_Driver, Ameen Rahman, Rajesh Borundia


Following changes are made:
1.Obtain capabilities of Nic partition.
2.Configure tx bandwidth of particular Nic partition.
3.Configure the eswitch for setting port mirroring, enable mac
learning, promiscous mode.

Signed-off-by: Rajesh K Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h      |   77 ++++++-
 drivers/net/qlcnic/qlcnic_ctx.c  |   90 ++------
 drivers/net/qlcnic/qlcnic_main.c |  450 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 542 insertions(+), 75 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 3675678..60ea7cb 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -959,8 +959,6 @@ struct qlcnic_adapter {
        u16 switch_mode;
        u16 max_tx_ques;
        u16 max_rx_ques;
-       u16 min_tx_bw;
-       u16 max_tx_bw;
        u16 max_mtu;

        u32 fw_hal_version;
@@ -984,7 +982,7 @@ struct qlcnic_adapter {

        u64 dev_rst_time;

-       struct qlcnic_pci_info *npars;
+       struct qlcnic_npar_info *npars;
        struct qlcnic_eswitch *eswitch;
        struct qlcnic_nic_template *nic_ops;

@@ -1042,6 +1040,18 @@ struct qlcnic_pci_info {
        u8      reserved2[106];
 };

+struct qlcnic_npar_info {
+       u16     vlan_id;
+       u8      phy_port;
+       u8      type;
+       u8      active;
+       u8      enable_pm;
+       u8      dest_npar;
+       u8      host_vlan_tag;
+       u8      promisc_mode;
+       u8      discard_tagged;
+       u8      mac_learning;
+};
 struct qlcnic_eswitch {
        u8      port;
        u8      active_vports;
@@ -1057,6 +1067,63 @@ struct qlcnic_eswitch {
 #define QLCNIC_SWITCH_PORT_MIRRORING   BIT_4
 };

+
+/* Return codes for Error handling */
+#define QL_STATUS_INVALID_PARAM        -1
+
+#define MAX_BW                 10000
+#define MIN_BW                 100
+#define MAX_VLAN_ID            4095
+#define MIN_VLAN_ID            2
+#define MAX_TX_QUEUES          1
+#define MAX_RX_QUEUES          4
+#define DEFAULT_MAC_LEARN      1
+
+#define IS_VALID_VLAN(vlan)    (vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
+#define IS_VALID_BW(bw)                (bw >= MIN_BW && bw <= MAX_BW \
+                                                       && (bw % 100) == 0)
+#define IS_VALID_TX_QUEUES(que)        (que > 0 && que <= MAX_TX_QUEUES)
+#define IS_VALID_RX_QUEUES(que)        (que > 0 && que <= MAX_RX_QUEUES)
+#define IS_VALID_MODE(mode)    (mode == 0 || mode == 1)
+
+struct qlcnic_pci_func_cfg {
+       u16     func_type;
+       u16     min_bw;
+       u16     max_bw;
+       u16     port_num;
+       u8      pci_func;
+       u8      func_state;
+       u8      def_mac_addr[6];
+};
+
+struct qlcnic_npar_func_cfg {
+       u32     fw_capab;
+       u16     port_num;
+       u16     min_bw;
+       u16     max_bw;
+       u16     max_tx_queues;
+       u16     max_rx_queues;
+       u8      pci_func;
+       u8      op_mode;
+};
+
+struct qlcnic_pm_func_cfg {
+       u8      pci_func;
+       u8      action;
+       u8      dest_npar;
+       u8      reserved[5];
+};
+
+struct qlcnic_esw_func_cfg {
+       u16     vlan_id;
+       u8      pci_func;
+       u8      host_vlan_tag;
+       u8      promisc_mode;
+       u8      discard_tagged;
+       u8      mac_learning;
+       u8      reserved;
+};
+
 int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
 int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);

@@ -1169,9 +1236,9 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 /* Management functions */
 int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
 int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
-int qlcnic_get_nic_info(struct qlcnic_adapter *, u8);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
 int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
-int qlcnic_get_pci_info(struct qlcnic_adapter *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
 int qlcnic_reset_partition(struct qlcnic_adapter *, u8);

 /*  eSwitch management functions */
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 7969a7a..cdd44b4 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -611,7 +611,8 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 }

 /* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+                               struct qlcnic_info *npar_info, u8 func_id)
 {
        int     err;
        dma_addr_t nic_dma_t;
@@ -635,29 +636,23 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
                        QLCNIC_CDRP_CMD_GET_NIC_INFO);

        if (err == QLCNIC_RCODE_SUCCESS) {
-               adapter->physical_port = le16_to_cpu(nic_info->phys_port);
-               adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
-               adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
-               adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-               adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-               adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
-               adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
-               adapter->capabilities = le32_to_cpu(nic_info->capabilities);
-               adapter->max_mac_filters = nic_info->max_mac_filters;
-
-               if (adapter->capabilities & BIT_6)
-                       adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-               else
-                       adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+               npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+               npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+               npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+               npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+               npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+               npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+               npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+               npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);

                dev_info(&adapter->pdev->dev,
                        "phy port: %d switch_mode: %d,\n"
                        "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
                        "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-                       adapter->physical_port, adapter->switch_mode,
-                       adapter->max_tx_ques, adapter->max_rx_ques,
-                       adapter->min_tx_bw, adapter->max_tx_bw,
-                       adapter->max_mtu, adapter->capabilities);
+                       npar_info->phys_port, npar_info->switch_mode,
+                       npar_info->max_tx_ques, npar_info->max_rx_ques,
+                       npar_info->min_tx_bw, npar_info->max_tx_bw,
+                       npar_info->max_mtu, npar_info->capabilities);
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get nic info%d\n", err);
@@ -672,7 +667,6 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
 int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 {
        int err = -EIO;
-       u32 func_state;
        dma_addr_t nic_dma_t;
        void *nic_info_addr;
        struct qlcnic_info *nic_info;
@@ -681,17 +675,6 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
        if (adapter->op_mode != QLCNIC_MGMT_FUNC)
                return err;

-       if (qlcnic_api_lock(adapter))
-               return err;
-
-       func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-       if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
-               qlcnic_api_unlock(adapter);
-               return err;
-       }
-
-       qlcnic_api_unlock(adapter);
-
        nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
                        &nic_dma_t);
        if (!nic_info_addr)
@@ -716,7 +699,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
                        adapter->fw_hal_version,
                        MSD(nic_dma_t),
                        LSD(nic_dma_t),
-                       nic_size,
+                       ((nic->pci_func << 16) | nic_size),
                        QLCNIC_CDRP_CMD_SET_NIC_INFO);

        if (err != QLCNIC_RCODE_SUCCESS) {
@@ -730,7 +713,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 }

 /* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+                               struct qlcnic_pci_info *pci_info)
 {
        int err = 0, i;
        dma_addr_t pci_info_dma_t;
@@ -745,21 +729,6 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
                return -ENOMEM;
        memset(pci_info_addr, 0, pci_size);

-       if (!adapter->npars)
-               adapter->npars = kzalloc(pci_size, GFP_KERNEL);
-       if (!adapter->npars) {
-               err = -ENOMEM;
-               goto err_npar;
-       }
-
-       if (!adapter->eswitch)
-               adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
-                               QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
-       if (!adapter->eswitch) {
-               err = -ENOMEM;
-               goto err_eswitch;
-       }
-
        npar = (struct qlcnic_pci_info *) pci_info_addr;
        err = qlcnic_issue_cmd(adapter,
                        adapter->ahw.pci_func,
@@ -770,31 +739,24 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
                        QLCNIC_CDRP_CMD_GET_PCI_INFO);

        if (err == QLCNIC_RCODE_SUCCESS) {
-               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
-                       adapter->npars[i].id = le32_to_cpu(npar->id);
-                       adapter->npars[i].active = le32_to_cpu(npar->active);
-                       adapter->npars[i].type = le32_to_cpu(npar->type);
-                       adapter->npars[i].default_port =
+               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
+                       pci_info->id = le32_to_cpu(npar->id);
+                       pci_info->active = le32_to_cpu(npar->active);
+                       pci_info->type = le32_to_cpu(npar->type);
+                       pci_info->default_port =
                                le32_to_cpu(npar->default_port);
-                       adapter->npars[i].tx_min_bw =
+                       pci_info->tx_min_bw =
                                le32_to_cpu(npar->tx_min_bw);
-                       adapter->npars[i].tx_max_bw =
+                       pci_info->tx_max_bw =
                                le32_to_cpu(npar->tx_max_bw);
-                       memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
+                       memcpy(pci_info->mac, npar->mac, ETH_ALEN);
                }
        } else {
                dev_err(&adapter->pdev->dev,
                        "Failed to get PCI Info%d\n", err);
-               kfree(adapter->npars);
                err = -EIO;
        }
-       goto err_npar;
-
-err_eswitch:
-       kfree(adapter->npars);
-       adapter->npars = NULL;

-err_npar:
        pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
                pci_info_dma_t);
        return err;
@@ -1012,9 +974,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
        if (err != QLCNIC_RCODE_SUCCESS) {
                dev_err(&adapter->pdev->dev,
                        "Failed to configure eswitch port%d\n", eswitch->port);
-               eswitch->flags |= QLCNIC_SWITCH_ENABLE;
        } else {
-               eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
                dev_info(&adapter->pdev->dev,
                        "Configured eSwitch for port %d\n", eswitch->port);
        }
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 981aa91..18e2b2e 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -476,6 +476,53 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
 }

 static int
+qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+{
+       struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+       int i, ret = 0, err;
+       u8 pfn;
+
+       if (!adapter->npars)
+               adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
+                               QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
+       if (!adapter->npars)
+               return -ENOMEM;
+
+       if (!adapter->eswitch)
+               adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+                               QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+       if (!adapter->eswitch) {
+               err = -ENOMEM;
+               goto err_eswitch;
+       }
+
+       ret = qlcnic_get_pci_info(adapter, pci_info);
+       if (!ret) {
+               for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+                       pfn = pci_info[i].id;
+                       if (pfn > QLCNIC_MAX_PCI_FUNC)
+                               return QL_STATUS_INVALID_PARAM;
+                       adapter->npars[pfn].active = pci_info[i].active;
+                       adapter->npars[pfn].type = pci_info[i].type;
+                       adapter->npars[pfn].phy_port = pci_info[i].default_port;
+                       adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+               }
+
+               for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+                       adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+
+               return ret;
+       }
+
+       kfree(adapter->eswitch);
+       adapter->eswitch = NULL;
+err_eswitch:
+       kfree(adapter->npars);
+
+       return ret;
+}
+
+static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
        u8 id;
@@ -494,7 +541,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)

        if (qlcnic_config_npars) {
                for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-                       id = adapter->npars[i].id;
+                       id = i;
                        if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
                                id == adapter->ahw.pci_func)
                                continue;
@@ -519,6 +566,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 {
        void __iomem *msix_base_addr;
        void __iomem *priv_op;
+       struct qlcnic_info nic_info;
        u32 func;
        u32 msix_base;
        u32 op_mode, priv_level;
@@ -533,7 +581,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
        adapter->ahw.pci_func = func;

-       qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+       if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+               adapter->capabilities = nic_info.capabilities;
+
+               if (adapter->capabilities & BIT_6)
+                       adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+               else
+                       adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+       }

        if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
                adapter->nic_ops = &qlcnic_ops;
@@ -552,7 +607,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
        case QLCNIC_MGMT_FUNC:
                adapter->op_mode = QLCNIC_MGMT_FUNC;
                adapter->nic_ops = &qlcnic_ops;
-               qlcnic_get_pci_info(adapter);
+               qlcnic_init_pci_info(adapter);
                /* Set privilege level for other functions */
                qlcnic_set_function_modes(adapter);
                dev_info(&adapter->pdev->dev,
@@ -654,7 +709,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
        int i, offset, val;
        int *ptr32;
        struct pci_dev *pdev = adapter->pdev;
-
+       struct qlcnic_info nic_info;
        adapter->driver_mismatch = 0;

        ptr32 = (int *)&serial_num;
@@ -696,7 +751,15 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
                adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
        }

-       qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+       if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+               adapter->physical_port = nic_info.phys_port;
+               adapter->switch_mode = nic_info.switch_mode;
+               adapter->max_tx_ques = nic_info.max_tx_ques;
+               adapter->max_rx_ques = nic_info.max_rx_ques;
+               adapter->capabilities = nic_info.capabilities;
+               adapter->max_mac_filters = nic_info.max_mac_filters;
+               adapter->max_mtu = nic_info.max_mtu;
+       }

        adapter->msix_supported = !!use_msi_x;
        adapter->rss_supported = !!use_msi_x;
@@ -2822,6 +2885,364 @@ static struct bin_attribute bin_attr_mem = {
        .write = qlcnic_sysfs_write_mem,
 };

+int
+validate_pm_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+       u8 src_pci_func, s_esw_id, d_esw_id;
+       u8 dest_pci_func;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               src_pci_func = pm_cfg[i].pci_func;
+               dest_pci_func = pm_cfg[i].dest_npar;
+               if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
+                               || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (!IS_VALID_MODE(pm_cfg[i].action))
+                       return QL_STATUS_INVALID_PARAM;
+
+               s_esw_id = adapter->npars[src_pci_func].phy_port;
+               d_esw_id = adapter->npars[dest_pci_func].phy_port;
+
+               if (s_esw_id != d_esw_id)
+                       return QL_STATUS_INVALID_PARAM;
+
+       }
+       return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_pm_func_cfg *pm_cfg;
+       u32 id, action, pci_func;
+       int count, rem, i, ret;
+
+       count   = size / sizeof(struct qlcnic_pm_func_cfg);
+       rem     = size % sizeof(struct qlcnic_pm_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+       ret = validate_pm_config(adapter, pm_cfg, count);
+       if (ret)
+               return ret;
+       for (i = 0; i < count; i++) {
+               pci_func = pm_cfg[i].pci_func;
+               action = pm_cfg[i].action;
+               id = adapter->npars[pci_func].phy_port;
+               ret = qlcnic_config_port_mirroring(adapter, id,
+                                               action, pci_func);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < count; i++) {
+               pci_func = pm_cfg[i].pci_func;
+               id = adapter->npars[pci_func].phy_port;
+               adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
+               adapter->npars[pci_func].dest_npar = id;
+       }
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+       int i;
+
+       if (size != sizeof(pm_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+                       continue;
+               pm_cfg[i].action = adapter->npars[i].enable_pm;
+               pm_cfg[i].dest_npar = 0;
+               pm_cfg[i].pci_func = i;
+       }
+       memcpy(buf, &pm_cfg, size);
+
+       return size;
+}
+
+int
+validate_esw_config(struct qlcnic_adapter *adapter,
+                       struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+       u8 pci_func;
+       int i;
+
+       for (i = 0; i < count; i++) {
+               pci_func = esw_cfg[i].pci_func;
+               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (esw_cfg->host_vlan_tag == 1)
+                       if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+                               return QL_STATUS_INVALID_PARAM;
+
+               if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
+                               || !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
+                               || !IS_VALID_MODE(esw_cfg[i].mac_learning)
+                               || !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+                       return QL_STATUS_INVALID_PARAM;
+       }
+
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_esw_func_cfg *esw_cfg;
+       u8 id, discard_tagged, promsc_mode, mac_learn;
+       u8 vlan_tagging, pci_func, vlan_id;
+       int count, rem, i, ret;
+
+       count   = size / sizeof(struct qlcnic_esw_func_cfg);
+       rem     = size % sizeof(struct qlcnic_esw_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+       ret = validate_esw_config(adapter, esw_cfg, count);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < count; i++) {
+               pci_func = esw_cfg[i].pci_func;
+               id = adapter->npars[pci_func].phy_port;
+               vlan_tagging = esw_cfg[i].host_vlan_tag;
+               promsc_mode = esw_cfg[i].promisc_mode;
+               mac_learn = esw_cfg[i].mac_learning;
+               vlan_id = esw_cfg[i].vlan_id;
+               discard_tagged = esw_cfg[i].discard_tagged;
+               ret = qlcnic_config_switch_port(adapter, id, vlan_tagging,
+                                               discard_tagged,
+                                               promsc_mode,
+                                               mac_learn,
+                                               pci_func,
+                                               vlan_id);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < count; i++) {
+               pci_func = esw_cfg[i].pci_func;
+               adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
+               adapter->npars[pci_func].mac_learning = esw_cfg[i].mac_learning;
+               adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
+               adapter->npars[pci_func].discard_tagged =
+                                               esw_cfg[i].discard_tagged;
+               adapter->npars[pci_func].host_vlan_tag =
+                                               esw_cfg[i].host_vlan_tag;
+       }
+
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+       int i;
+
+       if (size != sizeof(esw_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+                       continue;
+
+               esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
+               esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
+               esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
+               esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
+               esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+       }
+       memcpy(buf, &esw_cfg, size);
+
+       return size;
+}
+
+int
+validate_npar_config(struct qlcnic_adapter *adapter,
+                               struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+       u8 pci_func, i;
+
+       for (i = 0; i < count; i++) {
+               pci_func = np_cfg[i].pci_func;
+               if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+                       return QL_STATUS_INVALID_PARAM;
+
+               if (!IS_VALID_BW(np_cfg[i].min_bw)
+                               || !IS_VALID_BW(np_cfg[i].max_bw)
+                               || !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
+                               || !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
+                       return QL_STATUS_INVALID_PARAM;
+       }
+       return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_info nic_info;
+       struct qlcnic_npar_func_cfg *np_cfg;
+       int i, count, rem, ret;
+       u8 pci_func;
+
+       count   = size / sizeof(struct qlcnic_npar_func_cfg);
+       rem     = size % sizeof(struct qlcnic_npar_func_cfg);
+       if (rem)
+               return QL_STATUS_INVALID_PARAM;
+
+       np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+       ret = validate_npar_config(adapter, np_cfg, count);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < count ; i++) {
+               pci_func = np_cfg[i].pci_func;
+               ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
+               if (ret)
+                       return ret;
+               nic_info.pci_func = pci_func;
+               nic_info.min_tx_bw = np_cfg[i].min_bw;
+               nic_info.max_tx_bw = np_cfg[i].max_bw;
+               ret = qlcnic_set_nic_info(adapter, &nic_info);
+               if (ret)
+                       return ret;
+       }
+
+       return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_info nic_info;
+       struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+       int i, ret;
+
+       if (size != sizeof(np_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+               if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+                       continue;
+               ret = qlcnic_get_nic_info(adapter, &nic_info, i);
+               if (ret)
+                       return ret;
+
+               np_cfg[i].pci_func = i;
+               np_cfg[i].op_mode = nic_info.op_mode;
+               np_cfg[i].port_num = nic_info.phys_port;
+               np_cfg[i].fw_capab = nic_info.capabilities;
+               np_cfg[i].min_bw = nic_info.min_tx_bw ;
+               np_cfg[i].max_bw = nic_info.max_tx_bw;
+               np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+               np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+       }
+       memcpy(buf, &np_cfg, size);
+       return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
+       struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+       struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+       struct qlcnic_pci_info  pci_info[QLCNIC_MAX_PCI_FUNC];
+       int i, ret;
+
+       if (size != sizeof(pci_cfg))
+               return QL_STATUS_INVALID_PARAM;
+
+       ret = qlcnic_get_pci_info(adapter, pci_info);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+               pci_cfg[i].pci_func = pci_info[i].id;
+               pci_cfg[i].func_type = pci_info[i].type;
+               pci_cfg[i].port_num = pci_info[i].default_port;
+               pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+               pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+               memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+       }
+       memcpy(buf, &pci_cfg, size);
+       return size;
+
+}
+static struct bin_attribute bin_attr_npar_config = {
+       .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_npar_config,
+       .write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+       .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_pci_config,
+       .write = NULL,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+       .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_esw_config,
+       .write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+       .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+       .size = 0,
+       .read = qlcnic_sysfs_read_pm_config,
+       .write = qlcnic_sysfs_write_pm_config,
+};
+
 static void
 qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
 {
@@ -2853,6 +3274,18 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
                dev_info(dev, "failed to create crb sysfs entry\n");
        if (device_create_bin_file(dev, &bin_attr_mem))
                dev_info(dev, "failed to create mem sysfs entry\n");
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+                       adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return;
+       if (device_create_bin_file(dev, &bin_attr_pci_config))
+               dev_info(dev, "failed to create pci config sysfs entry");
+       if (device_create_bin_file(dev, &bin_attr_npar_config))
+               dev_info(dev, "failed to create npar config sysfs entry");
+       if (device_create_bin_file(dev, &bin_attr_esw_config))
+               dev_info(dev, "failed to create esw config sysfs entry");
+       if (device_create_bin_file(dev, &bin_attr_pm_config))
+               dev_info(dev, "failed to create pm config sysfs entry");
+
 }


@@ -2864,6 +3297,13 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
        device_remove_file(dev, &dev_attr_diag_mode);
        device_remove_bin_file(dev, &bin_attr_crb);
        device_remove_bin_file(dev, &bin_attr_mem);
+       if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+                       adapter->op_mode != QLCNIC_MGMT_FUNC)
+               return;
+       device_remove_bin_file(dev, &bin_attr_pci_config);
+       device_remove_bin_file(dev, &bin_attr_npar_config);
+       device_remove_bin_file(dev, &bin_attr_esw_config);
+       device_remove_bin_file(dev, &bin_attr_pm_config);
 }

 #ifdef CONFIG_INET
--
1.7.1


^ permalink raw reply related

* Re: [PATCH -next] ixgbe: use NETIF_F_LRO
From: Jeff Kirsher @ 2010-06-29 18:00 UTC (permalink / raw)
  To: Stanislaw Gruszka; +Cc: netdev
In-Reply-To: <20100629163857.0dcc1245@dhcp-lab-109.englab.brq.redhat.com>

On Tue, Jun 29, 2010 at 07:38, Stanislaw Gruszka <sgruszka@redhat.com> wrote:
> Both ETH_FLAG_LRO and NETIF_F_LRO have the same value, but NETIF_F_LRO
> is intended to use with netdev->features.
>
> Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
> ---
>  drivers/net/ixgbe/ixgbe_ethtool.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
> index 873b45e..e2ab4ae 100644
> --- a/drivers/net/ixgbe/ixgbe_ethtool.c
> +++ b/drivers/net/ixgbe/ixgbe_ethtool.c
> @@ -2227,7 +2227,7 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
>                                break;
>                        }
>                } else if (!adapter->rx_itr_setting) {
> -                       netdev->features &= ~ETH_FLAG_LRO;
> +                       netdev->features &= ~NETIF_F_LRO;
>                        if (data & ETH_FLAG_LRO)
>                                e_info("rx-usecs set to 0, "
>                                        "LRO/RSC cannot be enabled.\n");
> --

Thanks, I have added it to my queue of patches.

-- 
Cheers,
Jeff

^ permalink raw reply

* [PATCH net-next-2.6 2/2] qlcnic: Add support for configuring eswitch and npars
From: Anirban Chakraborty @ 2010-06-29 18:01 UTC (permalink / raw)
  To: David Miller, netdev@vger.kernel.org
  Cc: Dept_NX_Linux_NIC_Driver, Ameen Rahman, Rajesh Borundia

Forgot to put the From header in the patch. Please ignore the previous one 
in the series and apply this instead.
Sorry for any inconvenience.

-Anirban

From: Rajesh K Borundia <rajesh.borundia@qlogic.com>

Following changes are made:
1.Obtain capabilities of Nic partition.
2.Configure tx bandwidth of particular Nic partition.
3.Configure the eswitch for setting port mirroring, enable mac
learning, promiscous mode.

Signed-off-by: Rajesh K Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
---
 drivers/net/qlcnic/qlcnic.h      |   77 ++++++-
 drivers/net/qlcnic/qlcnic_ctx.c  |   90 ++------
 drivers/net/qlcnic/qlcnic_main.c |  450 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 542 insertions(+), 75 deletions(-)

diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 3675678..60ea7cb 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -959,8 +959,6 @@ struct qlcnic_adapter {
 	u16 switch_mode;
 	u16 max_tx_ques;
 	u16 max_rx_ques;
-	u16 min_tx_bw;
-	u16 max_tx_bw;
 	u16 max_mtu;
 
 	u32 fw_hal_version;
@@ -984,7 +982,7 @@ struct qlcnic_adapter {
 
 	u64 dev_rst_time;
 
-	struct qlcnic_pci_info *npars;
+	struct qlcnic_npar_info *npars;
 	struct qlcnic_eswitch *eswitch;
 	struct qlcnic_nic_template *nic_ops;
 
@@ -1042,6 +1040,18 @@ struct qlcnic_pci_info {
 	u8	reserved2[106];
 };
 
+struct qlcnic_npar_info {
+	u16	vlan_id;
+	u8	phy_port;
+	u8	type;
+	u8	active;
+	u8	enable_pm;
+	u8	dest_npar;
+	u8	host_vlan_tag;
+	u8	promisc_mode;
+	u8	discard_tagged;
+	u8	mac_learning;
+};
 struct qlcnic_eswitch {
 	u8	port;
 	u8	active_vports;
@@ -1057,6 +1067,63 @@ struct qlcnic_eswitch {
 #define QLCNIC_SWITCH_PORT_MIRRORING	BIT_4
 };
 
+
+/* Return codes for Error handling */
+#define QL_STATUS_INVALID_PARAM	-1
+
+#define MAX_BW			10000
+#define MIN_BW			100
+#define MAX_VLAN_ID		4095
+#define MIN_VLAN_ID		2
+#define MAX_TX_QUEUES		1
+#define MAX_RX_QUEUES		4
+#define DEFAULT_MAC_LEARN	1
+
+#define IS_VALID_VLAN(vlan)	(vlan >= MIN_VLAN_ID && vlan <= MAX_VLAN_ID)
+#define IS_VALID_BW(bw)		(bw >= MIN_BW && bw <= MAX_BW \
+							&& (bw % 100) == 0)
+#define IS_VALID_TX_QUEUES(que)	(que > 0 && que <= MAX_TX_QUEUES)
+#define IS_VALID_RX_QUEUES(que)	(que > 0 && que <= MAX_RX_QUEUES)
+#define IS_VALID_MODE(mode)	(mode == 0 || mode == 1)
+
+struct qlcnic_pci_func_cfg {
+	u16	func_type;
+	u16	min_bw;
+	u16	max_bw;
+	u16	port_num;
+	u8	pci_func;
+	u8	func_state;
+	u8	def_mac_addr[6];
+};
+
+struct qlcnic_npar_func_cfg {
+	u32	fw_capab;
+	u16	port_num;
+	u16	min_bw;
+	u16	max_bw;
+	u16	max_tx_queues;
+	u16	max_rx_queues;
+	u8	pci_func;
+	u8	op_mode;
+};
+
+struct qlcnic_pm_func_cfg {
+	u8	pci_func;
+	u8	action;
+	u8	dest_npar;
+	u8	reserved[5];
+};
+
+struct qlcnic_esw_func_cfg {
+	u16	vlan_id;
+	u8	pci_func;
+	u8	host_vlan_tag;
+	u8	promisc_mode;
+	u8	discard_tagged;
+	u8	mac_learning;
+	u8	reserved;
+};
+
 int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
 int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
 
@@ -1169,9 +1236,9 @@ void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
 /* Management functions */
 int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
 int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
-int qlcnic_get_nic_info(struct qlcnic_adapter *, u8);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, struct qlcnic_info *, u8);
 int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
-int qlcnic_get_pci_info(struct qlcnic_adapter *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *, struct qlcnic_pci_info*);
 int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
 
 /*  eSwitch management functions */
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 7969a7a..cdd44b4 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -611,7 +611,8 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
 }
 
 /* Get info of a NIC partition */
-int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
+				struct qlcnic_info *npar_info, u8 func_id)
 {
 	int	err;
 	dma_addr_t nic_dma_t;
@@ -635,29 +636,23 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
 			QLCNIC_CDRP_CMD_GET_NIC_INFO);
 
 	if (err == QLCNIC_RCODE_SUCCESS) {
-		adapter->physical_port = le16_to_cpu(nic_info->phys_port);
-		adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
-		adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
-		adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
-		adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
-		adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
-		adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
-		adapter->capabilities = le32_to_cpu(nic_info->capabilities);
-		adapter->max_mac_filters = nic_info->max_mac_filters;
-
-		if (adapter->capabilities & BIT_6)
-			adapter->flags |= QLCNIC_ESWITCH_ENABLED;
-		else
-			adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+		npar_info->phys_port = le16_to_cpu(nic_info->phys_port);
+		npar_info->switch_mode = le16_to_cpu(nic_info->switch_mode);
+		npar_info->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+		npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+		npar_info->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+		npar_info->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+		npar_info->capabilities = le32_to_cpu(nic_info->capabilities);
+		npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu);
 
 		dev_info(&adapter->pdev->dev,
 			"phy port: %d switch_mode: %d,\n"
 			"\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
 			"\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
-			adapter->physical_port, adapter->switch_mode,
-			adapter->max_tx_ques, adapter->max_rx_ques,
-			adapter->min_tx_bw, adapter->max_tx_bw,
-			adapter->max_mtu, adapter->capabilities);
+			npar_info->phys_port, npar_info->switch_mode,
+			npar_info->max_tx_ques, npar_info->max_rx_ques,
+			npar_info->min_tx_bw, npar_info->max_tx_bw,
+			npar_info->max_mtu, npar_info->capabilities);
 	} else {
 		dev_err(&adapter->pdev->dev,
 			"Failed to get nic info%d\n", err);
@@ -672,7 +667,6 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
 int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 {
 	int err = -EIO;
-	u32 func_state;
 	dma_addr_t nic_dma_t;
 	void *nic_info_addr;
 	struct qlcnic_info *nic_info;
@@ -681,17 +675,6 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 	if (adapter->op_mode != QLCNIC_MGMT_FUNC)
 		return err;
 
-	if (qlcnic_api_lock(adapter))
-		return err;
-
-	func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
-	if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
-		qlcnic_api_unlock(adapter);
-		return err;
-	}
-
-	qlcnic_api_unlock(adapter);
-
 	nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
 			&nic_dma_t);
 	if (!nic_info_addr)
@@ -716,7 +699,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 			adapter->fw_hal_version,
 			MSD(nic_dma_t),
 			LSD(nic_dma_t),
-			nic_size,
+			((nic->pci_func << 16) | nic_size),
 			QLCNIC_CDRP_CMD_SET_NIC_INFO);
 
 	if (err != QLCNIC_RCODE_SUCCESS) {
@@ -730,7 +713,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
 }
 
 /* Get PCI Info of a partition */
-int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
+				struct qlcnic_pci_info *pci_info)
 {
 	int err = 0, i;
 	dma_addr_t pci_info_dma_t;
@@ -745,21 +729,6 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
 		return -ENOMEM;
 	memset(pci_info_addr, 0, pci_size);
 
-	if (!adapter->npars)
-		adapter->npars = kzalloc(pci_size, GFP_KERNEL);
-	if (!adapter->npars) {
-		err = -ENOMEM;
-		goto err_npar;
-	}
-
-	if (!adapter->eswitch)
-		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
-				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
-	if (!adapter->eswitch) {
-		err = -ENOMEM;
-		goto err_eswitch;
-	}
-
 	npar = (struct qlcnic_pci_info *) pci_info_addr;
 	err = qlcnic_issue_cmd(adapter,
 			adapter->ahw.pci_func,
@@ -770,31 +739,24 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
 			QLCNIC_CDRP_CMD_GET_PCI_INFO);
 
 	if (err == QLCNIC_RCODE_SUCCESS) {
-		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
-			adapter->npars[i].id = le32_to_cpu(npar->id);
-			adapter->npars[i].active = le32_to_cpu(npar->active);
-			adapter->npars[i].type = le32_to_cpu(npar->type);
-			adapter->npars[i].default_port =
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++, pci_info++) {
+			pci_info->id = le32_to_cpu(npar->id);
+			pci_info->active = le32_to_cpu(npar->active);
+			pci_info->type = le32_to_cpu(npar->type);
+			pci_info->default_port =
 				le32_to_cpu(npar->default_port);
-			adapter->npars[i].tx_min_bw =
+			pci_info->tx_min_bw =
 				le32_to_cpu(npar->tx_min_bw);
-			adapter->npars[i].tx_max_bw =
+			pci_info->tx_max_bw =
 				le32_to_cpu(npar->tx_max_bw);
-			memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
+			memcpy(pci_info->mac, npar->mac, ETH_ALEN);
 		}
 	} else {
 		dev_err(&adapter->pdev->dev,
 			"Failed to get PCI Info%d\n", err);
-		kfree(adapter->npars);
 		err = -EIO;
 	}
-	goto err_npar;
-
-err_eswitch:
-	kfree(adapter->npars);
-	adapter->npars = NULL;
 
-err_npar:
 	pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
 		pci_info_dma_t);
 	return err;
@@ -1012,9 +974,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
 	if (err != QLCNIC_RCODE_SUCCESS) {
 		dev_err(&adapter->pdev->dev,
 			"Failed to configure eswitch port%d\n", eswitch->port);
-		eswitch->flags |= QLCNIC_SWITCH_ENABLE;
 	} else {
-		eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
 		dev_info(&adapter->pdev->dev,
 			"Configured eSwitch for port %d\n", eswitch->port);
 	}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 981aa91..18e2b2e 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -476,6 +476,53 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
 }
 
 static int
+qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
+{
+	struct qlcnic_pci_info pci_info[QLCNIC_MAX_PCI_FUNC];
+	int i, ret = 0, err;
+	u8 pfn;
+
+	if (!adapter->npars)
+		adapter->npars = kzalloc(sizeof(struct qlcnic_npar_info) *
+				QLCNIC_MAX_PCI_FUNC, GFP_KERNEL);
+	if (!adapter->npars)
+		return -ENOMEM;
+
+	if (!adapter->eswitch)
+		adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+				QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+	if (!adapter->eswitch) {
+		err = -ENOMEM;
+		goto err_eswitch;
+	}
+
+	ret = qlcnic_get_pci_info(adapter, pci_info);
+	if (!ret) {
+		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+			pfn = pci_info[i].id;
+			if (pfn > QLCNIC_MAX_PCI_FUNC)
+				return QL_STATUS_INVALID_PARAM;
+			adapter->npars[pfn].active = pci_info[i].active;
+			adapter->npars[pfn].type = pci_info[i].type;
+			adapter->npars[pfn].phy_port = pci_info[i].default_port;
+			adapter->npars[pfn].mac_learning = DEFAULT_MAC_LEARN;
+		}
+
+		for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++)
+			adapter->eswitch[i].flags |= QLCNIC_SWITCH_ENABLE;
+
+		return ret;
+	}
+
+	kfree(adapter->eswitch);
+	adapter->eswitch = NULL;
+err_eswitch:
+	kfree(adapter->npars);
+
+	return ret;
+}
+
+static int
 qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 {
 	u8 id;
@@ -494,7 +541,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
 
 	if (qlcnic_config_npars) {
 		for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
-			id = adapter->npars[i].id;
+			id = i;
 			if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
 				id == adapter->ahw.pci_func)
 				continue;
@@ -519,6 +566,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 {
 	void __iomem *msix_base_addr;
 	void __iomem *priv_op;
+	struct qlcnic_info nic_info;
 	u32 func;
 	u32 msix_base;
 	u32 op_mode, priv_level;
@@ -533,7 +581,14 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 	func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
 	adapter->ahw.pci_func = func;
 
-	qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+		adapter->capabilities = nic_info.capabilities;
+
+		if (adapter->capabilities & BIT_6)
+			adapter->flags |= QLCNIC_ESWITCH_ENABLED;
+		else
+			adapter->flags &= ~QLCNIC_ESWITCH_ENABLED;
+	}
 
 	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))	{
 		adapter->nic_ops = &qlcnic_ops;
@@ -552,7 +607,7 @@ qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
 	case QLCNIC_MGMT_FUNC:
 		adapter->op_mode = QLCNIC_MGMT_FUNC;
 		adapter->nic_ops = &qlcnic_ops;
-		qlcnic_get_pci_info(adapter);
+		qlcnic_init_pci_info(adapter);
 		/* Set privilege level for other functions */
 		qlcnic_set_function_modes(adapter);
 		dev_info(&adapter->pdev->dev,
@@ -654,7 +709,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 	int i, offset, val;
 	int *ptr32;
 	struct pci_dev *pdev = adapter->pdev;
-
+	struct qlcnic_info nic_info;
 	adapter->driver_mismatch = 0;
 
 	ptr32 = (int *)&serial_num;
@@ -696,7 +751,15 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 		adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
 	}
 
-	qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+	if (!qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func)) {
+		adapter->physical_port = nic_info.phys_port;
+		adapter->switch_mode = nic_info.switch_mode;
+		adapter->max_tx_ques = nic_info.max_tx_ques;
+		adapter->max_rx_ques = nic_info.max_rx_ques;
+		adapter->capabilities = nic_info.capabilities;
+		adapter->max_mac_filters = nic_info.max_mac_filters;
+		adapter->max_mtu = nic_info.max_mtu;
+	}
 
 	adapter->msix_supported = !!use_msi_x;
 	adapter->rss_supported = !!use_msi_x;
@@ -2822,6 +2885,364 @@ static struct bin_attribute bin_attr_mem = {
 	.write = qlcnic_sysfs_write_mem,
 };
 
+int
+validate_pm_config(struct qlcnic_adapter *adapter,
+			struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+	u8 src_pci_func, s_esw_id, d_esw_id;
+	u8 dest_pci_func;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		src_pci_func = pm_cfg[i].pci_func;
+		dest_pci_func = pm_cfg[i].dest_npar;
+		if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
+				|| dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_MODE(pm_cfg[i].action))
+			return QL_STATUS_INVALID_PARAM;
+
+		s_esw_id = adapter->npars[src_pci_func].phy_port;
+		d_esw_id = adapter->npars[dest_pci_func].phy_port;
+
+		if (s_esw_id != d_esw_id)
+			return QL_STATUS_INVALID_PARAM;
+
+	}
+	return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pm_func_cfg *pm_cfg;
+	u32 id, action, pci_func;
+	int count, rem, i, ret;
+
+	count	= size / sizeof(struct qlcnic_pm_func_cfg);
+	rem	= size % sizeof(struct qlcnic_pm_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+	ret = validate_pm_config(adapter, pm_cfg, count);
+	if (ret)
+		return ret;
+	for (i = 0; i < count; i++) {
+		pci_func = pm_cfg[i].pci_func;
+		action = pm_cfg[i].action;
+		id = adapter->npars[pci_func].phy_port;
+		ret = qlcnic_config_port_mirroring(adapter, id,
+						action, pci_func);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < count; i++) {
+		pci_func = pm_cfg[i].pci_func;
+		id = adapter->npars[pci_func].phy_port;
+		adapter->npars[pci_func].enable_pm = pm_cfg[i].action;
+		adapter->npars[pci_func].dest_npar = id;
+	}
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i;
+
+	if (size != sizeof(pm_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+		pm_cfg[i].action = adapter->npars[i].enable_pm;
+		pm_cfg[i].dest_npar = 0;
+		pm_cfg[i].pci_func = i;
+	}
+	memcpy(buf, &pm_cfg, size);
+
+	return size;
+}
+
+int
+validate_esw_config(struct qlcnic_adapter *adapter,
+			struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+	u8 pci_func;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (esw_cfg->host_vlan_tag == 1)
+			if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+				return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_MODE(esw_cfg[i].promisc_mode)
+				|| !IS_VALID_MODE(esw_cfg[i].host_vlan_tag)
+				|| !IS_VALID_MODE(esw_cfg[i].mac_learning)
+				|| !IS_VALID_MODE(esw_cfg[i].discard_tagged))
+			return QL_STATUS_INVALID_PARAM;
+	}
+
+	return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_esw_func_cfg *esw_cfg;
+	u8 id, discard_tagged, promsc_mode, mac_learn;
+	u8 vlan_tagging, pci_func, vlan_id;
+	int count, rem, i, ret;
+
+	count	= size / sizeof(struct qlcnic_esw_func_cfg);
+	rem	= size % sizeof(struct qlcnic_esw_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+	ret = validate_esw_config(adapter, esw_cfg, count);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		id = adapter->npars[pci_func].phy_port;
+		vlan_tagging = esw_cfg[i].host_vlan_tag;
+		promsc_mode = esw_cfg[i].promisc_mode;
+		mac_learn = esw_cfg[i].mac_learning;
+		vlan_id	= esw_cfg[i].vlan_id;
+		discard_tagged = esw_cfg[i].discard_tagged;
+		ret = qlcnic_config_switch_port(adapter, id, vlan_tagging,
+						discard_tagged,
+						promsc_mode,
+						mac_learn,
+						pci_func,
+						vlan_id);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < count; i++) {
+		pci_func = esw_cfg[i].pci_func;
+		adapter->npars[pci_func].promisc_mode = esw_cfg[i].promisc_mode;
+		adapter->npars[pci_func].mac_learning =	esw_cfg[i].mac_learning;
+		adapter->npars[pci_func].vlan_id = esw_cfg[i].vlan_id;
+		adapter->npars[pci_func].discard_tagged	=
+						esw_cfg[i].discard_tagged;
+		adapter->npars[pci_func].host_vlan_tag =
+						esw_cfg[i].host_vlan_tag;
+	}
+
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i;
+
+	if (size != sizeof(esw_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+
+		esw_cfg[i].host_vlan_tag = adapter->npars[i].host_vlan_tag;
+		esw_cfg[i].promisc_mode = adapter->npars[i].promisc_mode;
+		esw_cfg[i].discard_tagged = adapter->npars[i].discard_tagged;
+		esw_cfg[i].vlan_id = adapter->npars[i].vlan_id;
+		esw_cfg[i].mac_learning = adapter->npars[i].mac_learning;
+	}
+	memcpy(buf, &esw_cfg, size);
+
+	return size;
+}
+
+int
+validate_npar_config(struct qlcnic_adapter *adapter,
+				struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+	u8 pci_func, i;
+
+	for (i = 0; i < count; i++) {
+		pci_func = np_cfg[i].pci_func;
+		if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+			return QL_STATUS_INVALID_PARAM;
+
+		if (!IS_VALID_BW(np_cfg[i].min_bw)
+				|| !IS_VALID_BW(np_cfg[i].max_bw)
+				|| !IS_VALID_RX_QUEUES(np_cfg[i].max_rx_queues)
+				|| !IS_VALID_TX_QUEUES(np_cfg[i].max_tx_queues))
+			return QL_STATUS_INVALID_PARAM;
+	}
+	return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_info nic_info;
+	struct qlcnic_npar_func_cfg *np_cfg;
+	int i, count, rem, ret;
+	u8 pci_func;
+
+	count	= size / sizeof(struct qlcnic_npar_func_cfg);
+	rem	= size % sizeof(struct qlcnic_npar_func_cfg);
+	if (rem)
+		return QL_STATUS_INVALID_PARAM;
+
+	np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+	ret = validate_npar_config(adapter, np_cfg, count);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < count ; i++) {
+		pci_func = np_cfg[i].pci_func;
+		ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
+		if (ret)
+			return ret;
+		nic_info.pci_func = pci_func;
+		nic_info.min_tx_bw = np_cfg[i].min_bw;
+		nic_info.max_tx_bw = np_cfg[i].max_bw;
+		ret = qlcnic_set_nic_info(adapter, &nic_info);
+		if (ret)
+			return ret;
+	}
+
+	return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_info nic_info;
+	struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+	int i, ret;
+
+	if (size != sizeof(np_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+		if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+			continue;
+		ret = qlcnic_get_nic_info(adapter, &nic_info, i);
+		if (ret)
+			return ret;
+
+		np_cfg[i].pci_func = i;
+		np_cfg[i].op_mode = nic_info.op_mode;
+		np_cfg[i].port_num = nic_info.phys_port;
+		np_cfg[i].fw_capab = nic_info.capabilities;
+		np_cfg[i].min_bw = nic_info.min_tx_bw ;
+		np_cfg[i].max_bw = nic_info.max_tx_bw;
+		np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+		np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+	}
+	memcpy(buf, &np_cfg, size);
+	return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
+	struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+	struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+	struct qlcnic_pci_info	pci_info[QLCNIC_MAX_PCI_FUNC];
+	int i, ret;
+
+	if (size != sizeof(pci_cfg))
+		return QL_STATUS_INVALID_PARAM;
+
+	ret = qlcnic_get_pci_info(adapter, pci_info);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+		pci_cfg[i].pci_func = pci_info[i].id;
+		pci_cfg[i].func_type = pci_info[i].type;
+		pci_cfg[i].port_num = pci_info[i].default_port;
+		pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+		pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+		memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+	}
+	memcpy(buf, &pci_cfg, size);
+	return size;
+
+}
+static struct bin_attribute bin_attr_npar_config = {
+	.attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_npar_config,
+	.write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+	.attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_pci_config,
+	.write = NULL,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+	.attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_esw_config,
+	.write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+	.attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+	.size = 0,
+	.read = qlcnic_sysfs_read_pm_config,
+	.write = qlcnic_sysfs_write_pm_config,
+};
+
 static void
 qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
 {
@@ -2853,6 +3274,18 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
 		dev_info(dev, "failed to create crb sysfs entry\n");
 	if (device_create_bin_file(dev, &bin_attr_mem))
 		dev_info(dev, "failed to create mem sysfs entry\n");
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+			adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return;
+	if (device_create_bin_file(dev, &bin_attr_pci_config))
+		dev_info(dev, "failed to create pci config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_npar_config))
+		dev_info(dev, "failed to create npar config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_esw_config))
+		dev_info(dev, "failed to create esw config sysfs entry");
+	if (device_create_bin_file(dev, &bin_attr_pm_config))
+		dev_info(dev, "failed to create pm config sysfs entry");
+
 }
 
 
@@ -2864,6 +3297,13 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
 	device_remove_file(dev, &dev_attr_diag_mode);
 	device_remove_bin_file(dev, &bin_attr_crb);
 	device_remove_bin_file(dev, &bin_attr_mem);
+	if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED) ||
+			adapter->op_mode != QLCNIC_MGMT_FUNC)
+		return;
+	device_remove_bin_file(dev, &bin_attr_pci_config);
+	device_remove_bin_file(dev, &bin_attr_npar_config);
+	device_remove_bin_file(dev, &bin_attr_esw_config);
+	device_remove_bin_file(dev, &bin_attr_pm_config);
 }
 
 #ifdef CONFIG_INET
-- 
1.7.1


^ permalink raw reply related

* [PATCH v2] bonding: check if clients MAC addr has changed
From: Flavio Leitner @ 2010-06-29 18:24 UTC (permalink / raw)
  To: bonding-devel, Jay Vosburgh, netdev, Andy Gospodarek
  Cc: Flavio Leitner, Jay Vosburgh

When two systems using bonding devices in adaptive load
balancing (ALB) communicates with each other, an endless
ping-pong of ARP replies starts between these two systems.

What happens? In the ALB mode, bonding driver keeps track
of each client connected in a hash table, so it can do the
receive load balancing (RLB). This hash table is updated
when an ARP reply is received, then it scans for the client
entry, updates its MAC address and flag it to be announced
later. Therefore, two seconds later, the alb monitor runs
and send for each updated client entry two ARP replies
updating this specific client. The same process happens on
the receiving system, causing the endless ping-pong of arp
replies.

See more information including the relevant functions below:

   System 1                          System 2
    bond0                             bond0

   ping <system2>
    ARP request  --------->
                           <--------- ARP reply

+->rlb_arp_recv  <---------------------+   <--- loop begins
|  rlb_update_entry_from_arp           |
|  client_info->ntt = 1;               |
|  bond_info->rx_ntt = 1;              |
|                                      |
|         <communication succeed>      |
|                                      |
|  bond_alb_monitor                    |
|  rlb_update_rx_clients               |
|  rlb_update_client                   |
|  arp_create(ARPOP_REPLY)             |
|   send ARP reply -------------->     V
|   send ARP reply -------------->
|                               rlb_arp_recv
|                               rlb_update_entry_from_arp
|                               client_info->ntt = 1;
|                               bond_info->rx_ntt = 1;
|                           < snipped, same as in system 1>
+-------           <-------------- send ARP reply
                   <-------------- send ARP reply

Besides the unneeded networking traffic, this loop breaks
a cluster because a backup system can't take over the IP
address. There is always one system sending an ARP reply
poisoning the network.

This patch fixes the problem adding a check for the MAC
address before updating it. Thus, if the MAC address didn't
change, there is no need to update neither to announce it later.

Signed-off-by: Flavio Leitner <fleitner@redhat.com>
Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
---
 drivers/net/bonding/bond_alb.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 40fdc41..df48307 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -340,7 +340,8 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
 
 	if ((client_info->assigned) &&
 	    (client_info->ip_src == arp->ip_dst) &&
-	    (client_info->ip_dst == arp->ip_src)) {
+	    (client_info->ip_dst == arp->ip_src) &&
+	    (compare_ether_addr_64bits(client_info->mac_dst, arp->mac_src))) {
 		/* update the clients MAC address */
 		memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN);
 		client_info->ntt = 1;
-- 
1.7.0.1


^ permalink raw reply related

* RE: [REGRESSION] e1000e stopped working
From: Tantilov, Emil S @ 2010-06-29 18:37 UTC (permalink / raw)
  To: Maxim Levitsky; +Cc: netdev@vger.kernel.org, Allan, Bruce W, Pieper, Jeffrey E
In-Reply-To: <1277807529.19417.2.camel@localhost.localdomain>

Maxim Levitsky wrote:
> On Mon, 2010-06-28 at 18:09 -0700, Allan, Bruce W wrote:
>> On Monday, June 28, 2010 10:14 AM, Maxim Levitsky wrote:
>>> On Mon, 2010-06-28 at 10:04 -0700, Allan, Bruce W wrote:
>>>> On Sunday, June 27, 2010 10:47 AM, Maxim Levitsky wrote:
>>>>> On Sun, 2010-06-27 at 20:43 +0300, Maxim Levitsky wrote:
>>>>>> On Sun, 2010-06-27 at 20:29 +0300, Maxim Levitsky wrote:
>>>>>>> On Sun, 2010-06-27 at 20:27 +0300, Maxim Levitsky wrote:
>>>>>>>> Just that,
>>>>>>>> 
>>>>>>>> It doesn't receive anything from my internet router during
>>>>>>>> DHCP. 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 00:19.0 Ethernet controller [0200]: Intel Corporation 82566DC
>>>>>>>> 	Gigabit Network Connection [8086:104b] (rev 02) Subsystem:
>>>>>>>> 	Intel Corporation Device [8086:0001] Control: I/O+ Mem+
>>>>>>>> 	BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping-
>>>>>>>> 	SERR- FastB2B- DisINTx+ Status: Cap+ 66MHz- UDF- FastB2B-
>>>>>>>> 	ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
>>>>>>>> 	INTx- 	Latency: 0 Interrupt: pin A routed to IRQ 47 Region 0:
>>>>>>>> 	Memory at 50300000 (32-bit, non-prefetchable) [size=128K]
>>>>>>>> 	Region 1: Memory at 50324000 (32-bit, non-prefetchable)
>>>>>>>> 		[size=4K] Region 2: I/O ports at 30e0 [size=32]
>>>>>>>> 		Capabilities: [c8] Power Management version 2 Flags: PMEClk-
>>>>>>>> 	DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
>>>>>>>> 		Status: D0 PME-Enable- DSel=0 DScale=1 PME- Capabilities:
>>>>>>>> 	[d0] Message Signalled Interrupts: Mask- 64bit+ Queue=0/0
>>>>>>>> 	Enable+ Address: 00000000fee0100c  Data: 41c9 Kernel driver
>>>>>>>> in use: e1000e Kernel modules: e1000e 
>>>>>>>> 
>>>>>>>> I use vanilla tree, commit
>>>>>>>> bf2937695fe2330bfd8933a2310e7bdd2581dc2e
>>>>>>>> 
>>>>>>>> 
>>>>>>>> Best regards,
>>>>>>>> 	Maxim Levitsky
>>>>>>>> 
>>>>>>> 
>>>>>>> It appears to work now after reboot.
>>>>>>> Will keep a look for this.
>>>>>>> 
>>>>>>> Disregard for now.
>>>>>> 
>>>>>> 
>>>>>> Just s2ram cycle, problem is back.
>>>>>> Did full reboot (power off then on), same thing card doesn't
>>>>>> work... 
>>>>>> 
>>>>> 
>>>>> Yep, s2ram sometimes 'fixes', sometimes breaks the card.
>>>>> Something got broken in device initialization path.
>>>>> 
>>>>> Best regards,
>>>>>  	Maxim Levitsky
>>>> 
>>>> What distro are you using?  If RedHat, since you are using DHCP
>>>> will you please try putting a "LINKDELAY=10" in the
>>>> /etc/sysconfig/network-scripts/ifcfg-ethX config file.
>>>> 
>>> I use ubuntu 9.10
>>> 
>>>> Is there anything in the system log that might help narrow down the
>>>> issue?
>>> 
>>> Nothing, really nothing.
>>> It seems to detect link, dhcp client sends requests, but doesn't
>>> recieve a thing (even tried promisc mode - doesn't help)
>>> 
>>> 
>>> 
>>> Best regards,
>>> 	Maxim Levitsky
>> 
>> Since you say this is a regression, when did this last work for you
>> without this problem, i.e. which distro, which kernel? 
> 
> I always compile kernel, and last kernel I compiled here was vanilla
> 2.6.33-rc4.
> It works just fine.
> 
> I mostly use my laptop, and therefore didn't update kernel on my
> desktop for long time.
> 
> If I find some free time I try to bisect the problem.

Could you provide some additional info about your setup:
ethtool -e eth0
ethtool -d eth0
kernel config (if possible)

What is the model of your system/MB?

Thanks,
Emil


^ permalink raw reply

* [PATCH 1/3] gianfar: Implement workaround for eTSEC74 erratum
From: Anton Vorontsov @ 2010-06-29 20:59 UTC (permalink / raw)
  To: David Miller
  Cc: Manfred Rudigier, Sandeep Gopalpet, Andy Fleming, netdev,
	linuxppc-dev

MPC8313ECE says:

"If MACCFG2[Huge Frame]=0 and the Ethernet controller receives frames
 which are larger than MAXFRM, the controller truncates the frames to
 length MAXFRM and marks RxBD[TR]=1 to indicate the error. The controller
 also erroneously marks RxBD[TR]=1 if the received frame length is MAXFRM
 or MAXFRM-1, even though those frames are not truncated.
 No truncation or truncation error occurs if MACCFG2[Huge Frame]=1."

There are two options to workaround the issue:

"1. Set MACCFG2[Huge Frame]=1, so no truncation occurs for invalid large
 frames. Software can determine if a frame is larger than MAXFRM by
 reading RxBD[LG] or RxBD[Data Length].

 2. Set MAXFRM to 1538 (0x602) instead of the default 1536 (0x600), so
 normal-length frames are not marked as truncated. Software can examine
 RxBD[Data Length] to determine if the frame was larger than MAXFRM-2."

This patch implements the first workaround option by setting HUGEFRAME
bit, and gfar_clean_rx_ring() already checks the RxBD[Data Length].

Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
 drivers/net/Kconfig   |   10 ++++++++++
 drivers/net/gianfar.c |   36 ++++++++++++++++++++++++++++++++++--
 drivers/net/gianfar.h |   11 +++++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd..d3fcaba 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2400,6 +2400,16 @@ config GIANFAR
 	  This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx,
 	  and MPC86xx family of chips, and the FEC on the 8540.
 
+config GIANFAR_ERRATA
+	bool "Gianfar Ethernet errata handling"
+	depends on GIANFAR && (PPC_MPC837x || PPC_MPC831x)
+	default y
+	help
+	  With this option enabled, gianfar driver will able to cope with
+	  some TSEC errata.
+
+	  If unsure, say Y.
+
 config UCC_GETH
 	tristate "Freescale QE Gigabit Ethernet"
 	depends on QUICC_ENGINE
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 28b53d1..9c85d05 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -85,6 +85,7 @@
 #include <linux/net_tstamp.h>
 
 #include <asm/io.h>
+#include <asm/reg.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 #include <linux/module.h>
@@ -928,6 +929,31 @@ static void gfar_init_filer_table(struct gfar_private *priv)
 	}
 }
 
+static void gfar_detect_errata(struct gfar_private *priv)
+{
+	struct device *dev = &priv->ofdev->dev;
+	unsigned int pvr = mfspr(SPRN_PVR);
+	unsigned int svr = mfspr(SPRN_SVR);
+	unsigned int mod = (svr >> 16) & 0xfff6; /* w/o E suffix */
+	unsigned int rev = svr & 0xffff;
+
+	/* MPC8313 Rev 2.0 and higher; All MPC837x */
+	if ((pvr == 0x80850010 && mod == 0x80b0 && rev >= 0x0020) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_74;
+
+	if (priv->errata) {
+#ifdef CONFIG_GIANFAR_ERRATA
+		dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
+			priv->errata);
+#else
+		dev_warn(dev, "consider enabling CONFIG_GIANFAR_ERRATA, "
+			 "flags: 0x%x\n", priv->errata);
+		WARN_ON(1);
+#endif /* CONFIG_GIANFAR_ERRATA */
+	}
+}
+
 /* Set up the ethernet device structure, private data,
  * and anything else we need before we start */
 static int gfar_probe(struct of_device *ofdev,
@@ -960,6 +986,8 @@ static int gfar_probe(struct of_device *ofdev,
 	dev_set_drvdata(&ofdev->dev, priv);
 	regs = priv->gfargrp[0].regs;
 
+	gfar_detect_errata(priv);
+
 	/* Stop the DMA engine now, in case it was running before */
 	/* (The firmware could have used it, and left it running). */
 	gfar_halt(dev);
@@ -974,7 +1002,10 @@ static int gfar_probe(struct of_device *ofdev,
 	gfar_write(&regs->maccfg1, tempval);
 
 	/* Initialize MACCFG2. */
-	gfar_write(&regs->maccfg2, MACCFG2_INIT_SETTINGS);
+	tempval = MACCFG2_INIT_SETTINGS;
+	if (gfar_has_errata(priv, 74))
+		tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK;
+	gfar_write(&regs->maccfg2, tempval);
 
 	/* Initialize ECNTRL */
 	gfar_write(&regs->ecntrl, ECNTRL_INIT_SETTINGS);
@@ -2300,7 +2331,8 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu)
 	 * to allow huge frames, and to check the length */
 	tempval = gfar_read(&regs->maccfg2);
 
-	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE)
+	if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE ||
+			gfar_has_errata(priv, 74))
 		tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
 	else
 		tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index ac4a92e..d1e2986 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1025,6 +1025,16 @@ struct gfar_priv_grp {
 	char int_name_er[GFAR_INT_NAME_MAX];
 };
 
+enum gfar_errata {
+	GFAR_ERRATA_74		= 0x01,
+};
+
+#ifdef CONFIG_GIANFAR_ERRATA
+#define gfar_has_errata(priv, err) ((priv)->errata & GFAR_ERRATA_##err)
+#else
+#define gfar_has_errata(priv, err) 0
+#endif /* CONFIG_GIANFAR_ERRATA */
+
 /* Struct stolen almost completely (and shamelessly) from the FCC enet source
  * (Ok, that's not so true anymore, but there is a family resemblence)
  * The GFAR buffer descriptors track the ring buffers.  The rx_bd_base
@@ -1049,6 +1059,7 @@ struct gfar_private {
 	struct device_node *node;
 	struct net_device *ndev;
 	struct of_device *ofdev;
+	enum gfar_errata errata;
 
 	struct gfar_priv_grp gfargrp[MAXGROUPS];
 	struct gfar_priv_tx_q *tx_queue[MAX_TX_QS];
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 2/3] gianfar: Implement workaround for eTSEC76 erratum
From: Anton Vorontsov @ 2010-06-29 21:00 UTC (permalink / raw)
  To: David Miller
  Cc: Manfred Rudigier, Sandeep Gopalpet, Andy Fleming, netdev,
	linuxppc-dev

MPC8313ECE says:

"For TOE=1 huge or jumbo frames, the data required to generate the
 checksum may exceed the 2500-byte threshold beyond which the controller
 constrains itself to one memory fetch every 256 eTSEC system clocks.

 This throttling threshold is supposed to trigger only when the
 controller has sufficient data to keep transmit active for the duration
 of the memory fetches. The state machine handling this threshold,
 however, fails to take large TOE frames into account. As a result,
 TOE=1 frames larger than 2500 bytes often see excess delays before start
 of transmission."

This patch implements the workaround as suggested by the errata
document, i.e.:

"Limit TOE=1 frames to less than 2500 bytes to avoid excess delays due to
 memory throttling.
 When using packets larger than 2700 bytes, it is recommended to turn TOE
 off."

To be sure, we limit the TOE frames to 2500 bytes, and do software
checksumming instead.

Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
 drivers/net/gianfar.c |   19 +++++++++++++++++++
 drivers/net/gianfar.h |    1 +
 2 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 9c85d05..f8b9693 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -942,6 +942,11 @@ static void gfar_detect_errata(struct gfar_private *priv)
 			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
 		priv->errata |= GFAR_ERRATA_74;
 
+	/* MPC8313 and MPC837x all rev */
+	if ((pvr == 0x80850010 && mod == 0x80b0) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_76;
+
 	if (priv->errata) {
 #ifdef CONFIG_GIANFAR_ERRATA
 		dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
@@ -2018,6 +2023,20 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 	unsigned int nr_frags, nr_txbds, length;
 	union skb_shared_tx *shtx;
 
+	/*
+	 * TOE=1 frames larger than 2500 bytes may see excess delays
+	 * before start of transmission.
+	 */
+	if (unlikely(gfar_has_errata(priv, 76) &&
+			skb->ip_summed == CHECKSUM_PARTIAL &&
+			skb->len > 2500)) {
+		int ret;
+
+		ret = skb_checksum_help(skb);
+		if (ret)
+			return ret;
+	}
+
 	rq = skb->queue_mapping;
 	tx_queue = priv->tx_queue[rq];
 	txq = netdev_get_tx_queue(dev, rq);
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index d1e2986..fb308c8 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1027,6 +1027,7 @@ struct gfar_priv_grp {
 
 enum gfar_errata {
 	GFAR_ERRATA_74		= 0x01,
+	GFAR_ERRATA_76		= 0x02,
 };
 
 #ifdef CONFIG_GIANFAR_ERRATA
-- 
1.7.0.5


^ permalink raw reply related

* [PATCH 3/3] gianfar: Implement workaround for eTSEC-A002 erratum
From: Anton Vorontsov @ 2010-06-29 21:00 UTC (permalink / raw)
  To: David Miller
  Cc: Manfred Rudigier, Sandeep Gopalpet, Andy Fleming, netdev,
	linuxppc-dev

MPC8313ECE says:

"If the controller receives a 1- or 2-byte frame (such as an illegal
 runt packet or a packet with RX_ER asserted) before GRS is asserted
 and does not receive any other frames, the controller may fail to set
 GRSC even when the receive logic is completely idle. Any subsequent
 receive frame that is larger than two bytes will reset the state so
 the graceful stop can complete. A MAC receiver (Rx) reset will also
 reset the state."

This patch implements the proposed workaround:

"If IEVENT[GRSC] is still not set after the timeout, read the eTSEC
 register at offset 0xD1C. If bits 7-14 are the same as bits 23-30,
 the eTSEC Rx is assumed to be idle and the Rx can be safely reset.
 If the register fields are not equal, wait for another timeout
 period and check again."

Signed-off-by: Anton Vorontsov <avorontsov@mvista.com>
---
 drivers/net/gianfar.c |   40 +++++++++++++++++++++++++++++++++++++---
 drivers/net/gianfar.h |    1 +
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index f8b9693..f3da17a 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -947,6 +947,11 @@ static void gfar_detect_errata(struct gfar_private *priv)
 			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
 		priv->errata |= GFAR_ERRATA_76;
 
+	/* MPC8313 and MPC837x all rev */
+	if ((pvr == 0x80850010 && mod == 0x80b0) ||
+			(pvr == 0x80861010 && (mod & 0xfff9) == 0x80c0))
+		priv->errata |= GFAR_ERRATA_A002;
+
 	if (priv->errata) {
 #ifdef CONFIG_GIANFAR_ERRATA
 		dev_info(dev, "enabled errata workarounds, flags: 0x%x\n",
@@ -1577,6 +1582,29 @@ static void init_registers(struct net_device *dev)
 	gfar_write(&regs->minflr, MINFLR_INIT_SETTINGS);
 }
 
+static int __gfar_is_rx_idle(struct gfar_private *priv)
+{
+	u32 res;
+
+	/*
+	 * Normaly TSEC should not hang on GRS commands, so we should
+	 * actually wait for IEVENT_GRSC flag.
+	 */
+	if (likely(!gfar_has_errata(priv, A002)))
+		return 0;
+
+	/*
+	 * Read the eTSEC register at offset 0xD1C. If bits 7-14 are
+	 * the same as bits 23-30, the eTSEC Rx is assumed to be idle
+	 * and the Rx can be safely reset.
+	 */
+	res = gfar_read((void __iomem *)priv->gfargrp[0].regs + 0xd1c);
+	res &= 0x7f807f80;
+	if ((res & 0xffff) == (res >> 16))
+		return 1;
+
+	return 0;
+}
 
 /* Halt the receive and transmit queues */
 static void gfar_halt_nodisable(struct net_device *dev)
@@ -1600,12 +1628,18 @@ static void gfar_halt_nodisable(struct net_device *dev)
 	tempval = gfar_read(&regs->dmactrl);
 	if ((tempval & (DMACTRL_GRS | DMACTRL_GTS))
 	    != (DMACTRL_GRS | DMACTRL_GTS)) {
+		int ret;
+
 		tempval |= (DMACTRL_GRS | DMACTRL_GTS);
 		gfar_write(&regs->dmactrl, tempval);
 
-		spin_event_timeout(((gfar_read(&regs->ievent) &
-			 (IEVENT_GRSC | IEVENT_GTSC)) ==
-			 (IEVENT_GRSC | IEVENT_GTSC)), -1, 0);
+		do {
+			ret = spin_event_timeout(((gfar_read(&regs->ievent) &
+				 (IEVENT_GRSC | IEVENT_GTSC)) ==
+				 (IEVENT_GRSC | IEVENT_GTSC)), 1000000, 0);
+			if (!(gfar_read(&regs->ievent) & IEVENT_GRSC))
+				ret = __gfar_is_rx_idle(priv);
+		} while (!ret);
 	}
 }
 
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index fb308c8..e0907eb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1028,6 +1028,7 @@ struct gfar_priv_grp {
 enum gfar_errata {
 	GFAR_ERRATA_74		= 0x01,
 	GFAR_ERRATA_76		= 0x02,
+	GFAR_ERRATA_A002	= 0x04,
 };
 
 #ifdef CONFIG_GIANFAR_ERRATA
-- 
1.7.0.5

^ permalink raw reply related

* Re: [PATCH net-next-2.6 0/2] qlcnic: Driver fixes
From: David Miller @ 2010-06-29 22:12 UTC (permalink / raw)
  To: anirban.chakraborty; +Cc: netdev, ameen.rahman, Dept_NX_Linux_NIC_Driver
In-Reply-To: <alpine.OSX.2.00.1006291023350.30643@macintosh-2.qlogic.org>

From: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Date: Tue, 29 Jun 2010 10:51:59 -0700

> Resubmitting following two patches. Please apply.

Both applied, thanks.

^ permalink raw reply

* Re: [PATCH 1/3] gianfar: Implement workaround for eTSEC74 erratum
From: David Miller @ 2010-06-29 22:16 UTC (permalink / raw)
  To: avorontsov
  Cc: manfred.rudigier, Sandeep.Kumar, afleming, netdev, linuxppc-dev
In-Reply-To: <20100629205959.GA10905@oksana.dev.rtsoft.ru>


I really don't see any value at all to this config option,
the errata fixup code should be there all the time.

It really does no harm to be there in the cases where it isn't
used, and forcing users to turn this on is just another
obscure way to end up with an incorrect configuration.

^ permalink raw reply

* Re: [PATCH] net/core: use htons for skb->protocol
From: David Miller @ 2010-06-29 22:17 UTC (permalink / raw)
  To: sebastian; +Cc: netdev
In-Reply-To: <20100629163246.GA18647@Chamillionaire.breakpoint.cc>

From: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Date: Tue, 29 Jun 2010 18:32:46 +0200

> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> This is only noticed by people that are not doing everything correct in
> the first place.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

It's in network byte order so you should use ntohs().

^ permalink raw reply

* Re: [patch] isdn/gigaset: add a kfree() to error path
From: Tilman Schmidt @ 2010-06-29 22:18 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Hansjoerg Lipp, Karsten Keil, David S. Miller, gigaset307x-common,
	netdev, kernel-janitors
In-Reply-To: <20100628212046.GM19184@bicker>

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

Dan,

thanks for your patch. It is quite correct as it stands.
There is however another problem with that error path, in
that it also doesn't free the previously allocated channel.
I prefer not to carry two separate patches for that, so I'm
replacing your patch with the following augmented patch,
which I'll submit together with my other pending patches
for 2.6.36 soon:

Subject: [PATCH] isdn/gigaset: fix leaks in error path

Take care to free all previously allocated ressources in the
"out of memory" error path of the ISDN_CMD_DIAL branch.
Based on an original patch by Dan Carpenter.

Impact: bugfix
Reported-by: Dan Carpenter <error27@gmail.com>
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
---
 drivers/isdn/gigaset/i4l.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c
index 1d084bb..34bca37 100644
--- a/drivers/isdn/gigaset/i4l.c
+++ b/drivers/isdn/gigaset/i4l.c
@@ -419,6 +419,8 @@ oom:
 	dev_err(bcs->cs->dev, "out of memory\n");
 	for (i = 0; i < AT_NUM; ++i)
 		kfree(commands[i]);
+	kfree(commands);
+	gigaset_free_channel(bcs);
 	return -ENOMEM;
 }
 
-- 
1.6.5.3.298.g39add

-- 
Tilman Schmidt                    E-Mail: tilman@imap.cc
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Ungeöffnet mindestens haltbar bis: (siehe Rückseite)


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]

^ permalink raw reply related

* Re: [PATCH] net/core: use htons for skb->protocol
From: David Daney @ 2010-06-29 22:19 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior; +Cc: netdev
In-Reply-To: <20100629163246.GA18647@Chamillionaire.breakpoint.cc>

On 06/29/2010 09:32 AM, Sebastian Andrzej Siewior wrote:
> From: Sebastian Andrzej Siewior<bigeasy@linutronix.de>
>
> This is only noticed by people that are not doing everything correct in
> the first place.
>
> Signed-off-by: Sebastian Andrzej Siewior<bigeasy@linutronix.de>
> ---
>   net/core/dev.c |    3 ++-
>   1 files changed, 2 insertions(+), 1 deletions(-)
>
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 2b3bf53..78ad37c 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1541,7 +1541,8 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
>   				if (net_ratelimit())
>   					printk(KERN_CRIT "protocol %04x is "
>   					       "buggy, dev %s\n",
> -					       skb2->protocol, dev->name);
> +					       htons(skb2->protocol),

Would ntohs() be more appropriate here?  It looks like you are 
converting from network order to host order for printing.

David Daney

^ permalink raw reply

* Re: [PATCH 0/4] Extend Time Stamping
From: David Miller @ 2010-06-29 22:31 UTC (permalink / raw)
  To: richardcochran; +Cc: netdev
In-Reply-To: <cover.1277737222.git.richard.cochran@omicron.at>


Richard, last round I told you:

--------------------
By this I mean you should provide these inline helpers by default
then we can begin to put them into the drivers.
--------------------

This means no config option.

^ permalink raw reply

* Re: [PATCH] net/Makefile: conditionally descend to wireless and ieee802154
From: David Miller @ 2010-06-29 22:32 UTC (permalink / raw)
  To: nikai; +Cc: netdev, linux-kbuild, linux-kernel
In-Reply-To: <20100627120025.0232a9d0@absol.kitzblitz>

From: Nicolas Kaiser <nikai@nikai.net>
Date: Sun, 27 Jun 2010 12:00:25 +0200

> Don't descend to wireless and ieee802154 unless they are actually used.
> 
> Signed-off-by: Nicolas Kaiser <nikai@nikai.net>

Applied.

^ permalink raw reply

* Re: [PATCH] drivers/net/Makefile: conditionally descend to wireless
From: David Miller @ 2010-06-29 22:33 UTC (permalink / raw)
  To: nikai; +Cc: netdev, linux-kbuild, linux-kernel
In-Reply-To: <20100627234452.0f9d19f1@absol.kitzblitz>

From: Nicolas Kaiser <nikai@nikai.net>
Date: Sun, 27 Jun 2010 23:44:52 +0200

> Don't descend to wireless unless it is actually used.
> 
> Signed-off-by: Nicolas Kaiser <nikai@nikai.net>

Applied.

^ permalink raw reply

* Re: [patch] isdn/gigaset: add a kfree() to error path
From: Dan Carpenter @ 2010-06-29 22:33 UTC (permalink / raw)
  To: Tilman Schmidt
  Cc: Hansjoerg Lipp, Karsten Keil, David S. Miller, gigaset307x-common,
	netdev, kernel-janitors
In-Reply-To: <4C2A7127.3040609@imap.cc>

On Wed, Jun 30, 2010 at 12:18:15AM +0200, Tilman Schmidt wrote:
> Dan,
> 
> thanks for your patch. It is quite correct as it stands.
> There is however another problem with that error path, in
> that it also doesn't free the previously allocated channel.
> I prefer not to carry two separate patches for that, so I'm
> replacing your patch with the following augmented patch,
> which I'll submit together with my other pending patches
> for 2.6.36 soon:
> 

Good deal.

Acked-by: Dan Carpenter <error27@gmail.com>

regards,
dan carpenter


^ permalink raw reply

* PATCH 1/2] Remove obsolete comment about the lack of a TX Timer Callback -- which we ...
From: Casey Leedom @ 2010-06-29 22:53 UTC (permalink / raw)
  To: netdev

>From fab966adc65f1b500e261867b3cb26bf35482b36 Mon Sep 17 00:00:00 2001
From: Casey Leedom <leedom@chelsio.com>
Date: Tue, 29 Jun 2010 15:14:38 -0700
Subject: [PATCH 1/2] Remove obsolete comment about the lack of a TX Timer Callback -- which we
 now _do_ have ...


Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
 drivers/net/cxgb4vf/sge.c |   13 +------------
 1 files changed, 1 insertions(+), 12 deletions(-)

diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index f857d20..5c4a81d 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -1301,18 +1301,7 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
 		 * wait for acks to really free up the data the extra memory
 		 * is even less.  On the positive side we run the destructors
 		 * on the sending CPU rather than on a potentially different
-		 * completing CPU, usually a good thing.  We also run them
-		 * without holding our TX queue lock, unlike what
-		 * reclaim_completed_tx() would otherwise do.
-		 *
-		 * XXX Actually the above is somewhat incorrect since we don't
-		 * XXX yet have a periodic timer which reclaims TX Descriptors.
-		 * XXX What's our plan for this?
-		 * XXX
-		 * XXX Also, we don't currently have a TX Queue lock but
-		 * XXX that may be the result of not having any current
-		 * XXX asynchronous path for reclaiming completed TX
-		 * XXX Descriptors ...
+		 * completing CPU, usually a good thing.
 		 *
 		 * Run the destructor before telling the DMA engine about the
 		 * packet to make sure it doesn't complete and get freed
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/2] Use correct shift factor for extracting the SGE DMA Ingress Padding ...
From: Casey Leedom @ 2010-06-29 22:54 UTC (permalink / raw)
  To: netdev

>From d9aed637fc8a9f1bf1bccf6f23aed0342870f868 Mon Sep 17 00:00:00 2001
From: Casey Leedom <leedom@chelsio.com>
Date: Tue, 29 Jun 2010 15:15:11 -0700
Subject: [PATCH 2/2] Use correct shift factor for extracting the SGE DMA Ingress Padding
 Boundary.  Was accidentally using the register field's shift which was close
 enough (4 instead of the propper value of 5) that it actually sort of
 worked for various packet sizes ...


Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
 drivers/net/cxgb4vf/sge.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index 5c4a81d..3a7c02f 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -2432,7 +2432,7 @@ int t4vf_sge_init(struct adapter *adapter)
 	STAT_LEN = ((sge_params->sge_control & EGRSTATUSPAGESIZE) ? 128 : 64);
 	PKTSHIFT = PKTSHIFT_GET(sge_params->sge_control);
 	FL_ALIGN = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) +
-			 INGPADBOUNDARY_SHIFT);
+			 SGE_INGPADBOUNDARY_SHIFT);
 
 	/*
 	 * Set up tasklet timers.
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 0/2] cxgb4vf: small fixes to new driver
From: Casey Leedom @ 2010-06-29 22:52 UTC (permalink / raw)
  To: netdev

>From d9aed637fc8a9f1bf1bccf6f23aed0342870f868 Mon Sep 17 00:00:00 2001
From: Casey Leedom <leedom@chelsio.com>
Date: Tue, 29 Jun 2010 15:41:14 -0700
Subject: [PATCH 0/2] cxgb4vf: small fixes to new driver

  In my cxgb4vf driver testing I got very "lucky" and the use of an
incorrect shift factor just happened to work for the packet size I was
using. (sigh) (All of this happened because I had to translate our internal
version of the driver to use the different constant names used in the
kernel.org tree.)

Casey Leedom (2):
  Remove obsolete comment about the lack of a TX Timer Callback --
    which we now _do_ have ...

  Use correct shift factor for extracting the SGE DMA Ingress Padding  
    Boundary.  Was accidentally using the register field's shift which
    was close enough (4 instead of the propper value of 5) that it
    actually sort of worked for various packet sizes ...

 drivers/net/cxgb4vf/sge.c |   15 ++-------------
 1 files changed, 2 insertions(+), 13 deletions(-)


^ permalink raw reply

* Re: [PATCH 0/9] New cxgb4vf network driver for Chelsio T4 Virtual Function NIC
From: Casey Leedom @ 2010-06-29 23:02 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <201006290904.50370.leedom@chelsio.com>

| From: Casey Leedom <leedom@chelsio.com>
| Date: Tuesday, June 29, 2010 09:04 am
| 
|   Thank you and I'm sorry for the mess. (sigh) I'm using the Kubuntu
| supplied email client and I mistakenly assumed that its "Insert File"
| action would do the right job.  I'll just use Thunderbird from now on.

  Hopefully my latest effort at getting patches submitted will be better.  
There's evidently a way to get git to mail them directly with which I'm fighting, 
so in the mean time I disabled word wrap on my current mailer.  I will get 
someone here to help me out with the git (and stgit) patch support.

|   Odd that patch #3 didn't apply cleanly.  I'll do a "pull" and verify
| correct operation.

  I did a complete new pull, compared the submitted and the pulled source and 
found no differences.  I then did a thorough test run and discovered that I'd 
accidentally translated one of our internal symbolic names into the wrong 
kernel.org symbolic names.  By "luck" it worked for some packet sizes so I 
didn't catch it. (sigh)  I've submitted patches for that bug and the deletion of 
an obsolete comment which I forgot to get rid of earlier.

  I hope these new patches apply cleanly.  If not, just drop them and I'll got 
to remedial git school here and get someone to help me do it right.

Casey

^ permalink raw reply

* Re: [PATCH] s2io: read rx_packets count from the hardware stats
From: Jon Mason @ 2010-06-30  0:54 UTC (permalink / raw)
  To: Michal Schmidt
  Cc: netdev@vger.kernel.org, Ramkrishna Vepa, Sivakumar Subramani,
	Sreenivasa Honnur
In-Reply-To: <20100624233230.5864.67401.stgit@leela.lan>

On Thu, Jun 24, 2010 at 04:32:32PM -0700, Michal Schmidt wrote:
> Most of the statistics the s2io driver provides in /proc/net/dev
> it reads directly from the hardware counters. For some reason it does
> not do that for rx_packets. It counts rx_packets purely in software.
>
> A customer reported a bug where in /proc/net/dev the 'multicast' counter
> was increasing faster than 'packets' ( = rx_packets in the source code).
> This confuses userspace, especially snmpd.
>
> The hardware provides a counter for the total number of received
> frames (RMAC_VLD_FRMS) which the driver can use for the rx_packets
> statistic. By reading both statistics from the hardware it makes sure
> that all multicast frames are included in the total.

On the Xframe adapter, there is a issue with the multicast statistics
counter.  It includes broadcast and pause frames in its count.  This
is most likely the cause of the issue you are seeing.

While, looking over the patch you submitted, I noticed other issues
with the s2io_get_stats function.  I have a patch that I will push
soon that addresses the multicast issue, the issues I discovered, and
the octet issues Dave suggested.

Thanks,
Jon

>
> The customer tested a patch like this (only modified for RHEL5) with
> S2io Inc. Xframe II 10Gbps Ethernet (rev 02)
> and it fixed the problem.
>
> Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
> ---
>
>  drivers/net/s2io.c |   11 ++++++-----
>  drivers/net/s2io.h |    1 -
>  2 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
> index 668327c..eefc4b2 100644
> --- a/drivers/net/s2io.c
> +++ b/drivers/net/s2io.c
> @@ -4919,6 +4919,10 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
>               sp->stats.tx_packets;
>       sp->stats.tx_packets = le32_to_cpu(stats->tmac_frms);
>
> +     dev->stats.rx_packets += le32_to_cpu(stats->rmac_vld_frms) -
> +             sp->stats.rx_packets;
> +     sp->stats.rx_packets = le32_to_cpu(stats->rmac_vld_frms);
> +
>       dev->stats.tx_errors += le32_to_cpu(stats->tmac_any_err_frms) -
>               sp->stats.tx_errors;
>       sp->stats.tx_errors = le32_to_cpu(stats->tmac_any_err_frms);
> @@ -4935,12 +4939,11 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
>               sp->stats.rx_length_errors;
>       sp->stats.rx_length_errors = le64_to_cpu(stats->rmac_long_frms);
>
> -     /* collect per-ring rx_packets and rx_bytes */
> -     dev->stats.rx_packets = dev->stats.rx_bytes = 0;
> +     /* collect per-ring rx_bytes */
> +     dev->stats.rx_bytes = 0;
>       for (i = 0; i < config->rx_ring_num; i++) {
>               struct ring_info *ring = &mac_control->rings[i];
>
> -             dev->stats.rx_packets += ring->rx_packets;
>               dev->stats.rx_bytes += ring->rx_bytes;
>       }
>
> @@ -7455,8 +7458,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
>               }
>       }
>
> -     /* Updating statistics */
> -     ring_data->rx_packets++;
>       rxdp->Host_Control = 0;
>       if (sp->rxd_mode == RXD_MODE_1) {
>               int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
> diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
> index 47c36e0..4da9ab8 100644
> --- a/drivers/net/s2io.h
> +++ b/drivers/net/s2io.h
> @@ -747,7 +747,6 @@ struct ring_info {
>       struct buffAdd **ba;
>
>       /* per-Ring statistics */
> -     unsigned long rx_packets;
>       unsigned long rx_bytes;
>  } ____cacheline_aligned;
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

The information and any attached documents contained in this message
may be confidential and/or legally privileged.  The message is
intended solely for the addressee(s).  If you are not the intended
recipient, you are hereby notified that any use, dissemination, or
reproduction is strictly prohibited and may be unlawful.  If you are
not the intended recipient, please contact the sender immediately by
return e-mail and destroy all copies of the original message.

^ permalink raw reply

* [PATCHv2 net-next-2.6] 3c59x: Use fine-grained locks for MII and windowed register access
From: Ben Hutchings @ 2010-06-30  1:26 UTC (permalink / raw)
  To: David Miller; +Cc: steffen.klassert, netdev, chase.douglas, nordmark
In-Reply-To: <20100628.231812.35040625.davem@davemloft.net>

This avoids scheduling in atomic context and also means that IRQs
will only be deferred for relatively short periods of time.

Previously discussed in:
http://article.gmane.org/gmane.linux.network/155024

Reported-by: Arne Nordmark <nordmark@mech.kth.se>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
Added the missing spin_lock_init() calls.

Ben.

 drivers/net/3c59x.c |   68 ++++++++++++++++++++++++++++++--------------------
 1 files changed, 41 insertions(+), 27 deletions(-)

diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index beddef9..069a03f 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -644,9 +644,15 @@ struct vortex_private {
 	u16 deferred;						/* Resend these interrupts when we
 										 * bale from the ISR */
 	u16 io_size;						/* Size of PCI region (for release_region) */
-	spinlock_t lock;					/* Serialise access to device & its vortex_private */
-	struct mii_if_info mii;				/* MII lib hooks/info */
-	int window;					/* Register window */
+
+	/* Serialises access to hardware other than MII and variables below.
+	 * The lock hierarchy is rtnl_lock > lock > mii_lock > window_lock. */
+	spinlock_t lock;
+
+	spinlock_t mii_lock;		/* Serialises access to MII */
+	struct mii_if_info mii;		/* MII lib hooks/info */
+	spinlock_t window_lock;		/* Serialises access to windowed regs */
+	int window;			/* Register window */
 };
 
 static void window_set(struct vortex_private *vp, int window)
@@ -661,15 +667,23 @@ static void window_set(struct vortex_private *vp, int window)
 static u ## size							\
 window_read ## size(struct vortex_private *vp, int window, int addr)	\
 {									\
+	unsigned long flags;						\
+	u ## size ret;							\
+	spin_lock_irqsave(&vp->window_lock, flags);			\
 	window_set(vp, window);						\
-	return ioread ## size(vp->ioaddr + addr);			\
+	ret = ioread ## size(vp->ioaddr + addr);			\
+	spin_unlock_irqrestore(&vp->window_lock, flags);		\
+	return ret;							\
 }									\
 static void								\
 window_write ## size(struct vortex_private *vp, u ## size value,	\
 		     int window, int addr)				\
 {									\
+	unsigned long flags;						\
+	spin_lock_irqsave(&vp->window_lock, flags);			\
 	window_set(vp, window);						\
 	iowrite ## size(value, vp->ioaddr + addr);			\
+	spin_unlock_irqrestore(&vp->window_lock, flags);		\
 }
 DEFINE_WINDOW_IO(8)
 DEFINE_WINDOW_IO(16)
@@ -1181,6 +1195,8 @@ static int __devinit vortex_probe1(struct device *gendev,
 	}
 
 	spin_lock_init(&vp->lock);
+	spin_lock_init(&vp->mii_lock);
+	spin_lock_init(&vp->window_lock);
 	vp->gendev = gendev;
 	vp->mii.dev = dev;
 	vp->mii.mdio_read = mdio_read;
@@ -1784,7 +1800,6 @@ vortex_timer(unsigned long data)
 		pr_debug("dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
 	}
 
-	disable_irq_lockdep(dev->irq);
 	media_status = window_read16(vp, 4, Wn4_Media);
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
@@ -1805,10 +1820,7 @@ vortex_timer(unsigned long data)
 	case XCVR_MII: case XCVR_NWAY:
 		{
 			ok = 1;
-			/* Interrupts are already disabled */
-			spin_lock(&vp->lock);
 			vortex_check_media(dev, 0);
-			spin_unlock(&vp->lock);
 		}
 		break;
 	  default:					/* Other media types handled by Tx timeouts. */
@@ -1827,6 +1839,8 @@ vortex_timer(unsigned long data)
 	if (!ok) {
 		unsigned int config;
 
+		spin_lock_irq(&vp->lock);
+
 		do {
 			dev->if_port = media_tbl[dev->if_port].next;
 		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
@@ -1855,6 +1869,8 @@ vortex_timer(unsigned long data)
 		if (vortex_debug > 1)
 			pr_debug("wrote 0x%08x to Wn3_Config\n", config);
 		/* AKPM: FIXME: Should reset Rx & Tx here.  P60 of 3c90xc.pdf */
+
+		spin_unlock_irq(&vp->lock);
 	}
 
 leave_media_alone:
@@ -1862,7 +1878,6 @@ leave_media_alone:
 	  pr_debug("%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
 
-	enable_irq_lockdep(dev->irq);
 	mod_timer(&vp->timer, RUN_AT(next_tick));
 	if (vp->deferred)
 		iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -2051,9 +2066,11 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
 		int len = (skb->len + 3) & ~3;
 		vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len,
 						PCI_DMA_TODEVICE);
+		spin_lock_irq(&vp->window_lock);
 		window_set(vp, 7);
 		iowrite32(vp->tx_skb_dma, ioaddr + Wn7_MasterAddr);
 		iowrite16(len, ioaddr + Wn7_MasterLen);
+		spin_unlock_irq(&vp->window_lock);
 		vp->tx_skb = skb;
 		iowrite16(StartDMADown, ioaddr + EL3_CMD);
 		/* netif_wake_queue() will be called at the DMADone interrupt. */
@@ -2225,6 +2242,7 @@ vortex_interrupt(int irq, void *dev_id)
 		pr_debug("%s: interrupt, status %4.4x, latency %d ticks.\n",
 			   dev->name, status, ioread8(ioaddr + Timer));
 
+	spin_lock(&vp->window_lock);
 	window_set(vp, 7);
 
 	do {
@@ -2285,6 +2303,8 @@ vortex_interrupt(int irq, void *dev_id)
 		iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
 	} while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
 
+	spin_unlock(&vp->window_lock);
+
 	if (vortex_debug > 4)
 		pr_debug("%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
@@ -2806,37 +2826,22 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
 static int vortex_nway_reset(struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	rc = mii_nway_restart(&vp->mii);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_nway_restart(&vp->mii);
 }
 
 static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	rc = mii_ethtool_gset(&vp->mii, cmd);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_ethtool_gset(&vp->mii, cmd);
 }
 
 static int vortex_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct vortex_private *vp = netdev_priv(dev);
-	unsigned long flags;
-	int rc;
 
-	spin_lock_irqsave(&vp->lock, flags);
-	rc = mii_ethtool_sset(&vp->mii, cmd);
-	spin_unlock_irqrestore(&vp->lock, flags);
-	return rc;
+	return mii_ethtool_sset(&vp->mii, cmd);
 }
 
 static u32 vortex_get_msglevel(struct net_device *dev)
@@ -3059,6 +3064,8 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
 	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	unsigned int retval = 0;
 
+	spin_lock_bh(&vp->mii_lock);
+
 	if (mii_preamble_required)
 		mdio_sync(vp, 32);
 
@@ -3082,6 +3089,9 @@ static int mdio_read(struct net_device *dev, int phy_id, int location)
 			       4, Wn4_PhysicalMgmt);
 		mdio_delay(vp);
 	}
+
+	spin_unlock_bh(&vp->mii_lock);
+
 	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
 }
 
@@ -3091,6 +3101,8 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
 	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
 	int i;
 
+	spin_lock_bh(&vp->mii_lock);
+
 	if (mii_preamble_required)
 		mdio_sync(vp, 32);
 
@@ -3111,6 +3123,8 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
 			       4, Wn4_PhysicalMgmt);
 		mdio_delay(vp);
 	}
+
+	spin_unlock_bh(&vp->mii_lock);
 }
 
 /* ACPI: Advanced Configuration and Power Interface. */
-- 
1.7.1


-- 
Ben Hutchings
Once a job is fouled up, anything done to improve it makes it worse.

^ permalink raw reply related


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