#define ADDR_IN_WINDOW1(off)   \
        ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
 
+#define ADDR_IN_RANGE(addr, low, high) \
+       (((addr) < (high)) && ((addr) >= (low)))
+
 /*
  * normalize a 64MB crb address to 32MB PCI window
  * To use NETXEN_CRB_NORMALIZE, window _must_ be set to 1
 int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
 int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
 void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
+void netxen_pci_camqm_read_2M(struct netxen_adapter *, u64, u64 *);
+void netxen_pci_camqm_write_2M(struct netxen_adapter *, u64, u64);
 
 int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu);
 int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
 
 }
 #endif
 
-#define ADDR_IN_RANGE(addr, low, high) \
-       (((addr) < (high)) && ((addr) >= (low)))
-
 #define PCI_OFFSET_FIRST_RANGE(adapter, off)    \
        ((adapter)->ahw.pci_base0 + (off))
 #define PCI_OFFSET_SECOND_RANGE(adapter, off)   \
        return ret;
 }
 
+void
+netxen_pci_camqm_read_2M(struct netxen_adapter *adapter, u64 off, u64 *data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               NETXEN_PCI_CAMQM_2M_BASE + (off - NETXEN_PCI_CAMQM);
+
+       spin_lock(&adapter->ahw.mem_lock);
+       *data = readq(addr);
+       spin_unlock(&adapter->ahw.mem_lock);
+}
+
+void
+netxen_pci_camqm_write_2M(struct netxen_adapter *adapter, u64 off, u64 data)
+{
+       void __iomem *addr = adapter->ahw.pci_base0 +
+               NETXEN_PCI_CAMQM_2M_BASE + (off - NETXEN_PCI_CAMQM);
+
+       spin_lock(&adapter->ahw.mem_lock);
+       writeq(data, addr);
+       spin_unlock(&adapter->ahw.mem_lock);
+}
+
 #define MAX_CTL_CHECK   1000
 
 static int
 
 netxen_sysfs_validate_crb(struct netxen_adapter *adapter,
                loff_t offset, size_t size)
 {
+       size_t crb_size = 4;
+
        if (!(adapter->flags & NETXEN_NIC_DIAG_ENABLED))
                return -EIO;
 
-       if ((size != 4) || (offset & 0x3))
-               return  -EINVAL;
+       if (offset < NETXEN_PCI_CRBSPACE) {
+               if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+                       return -EINVAL;
 
-       if (offset < NETXEN_PCI_CRBSPACE)
-               return -EINVAL;
+               if (ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                               NETXEN_PCI_CAMQM_2M_END))
+                       crb_size = 8;
+               else
+                       return -EINVAL;
+       }
+
+       if ((size != crb_size) || (offset & (crb_size-1)))
+               return  -EINVAL;
 
        return 0;
 }
        struct device *dev = container_of(kobj, struct device, kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = netxen_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       data = NXRD32(adapter, offset);
-       memcpy(buf, &data, size);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id) &&
+               ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                       NETXEN_PCI_CAMQM_2M_END)) {
+               netxen_pci_camqm_read_2M(adapter, offset, &qmdata);
+               memcpy(buf, &qmdata, size);
+       } else {
+               data = NXRD32(adapter, offset);
+               memcpy(buf, &data, size);
+       }
+
        return size;
 }
 
        struct device *dev = container_of(kobj, struct device, kobj);
        struct netxen_adapter *adapter = dev_get_drvdata(dev);
        u32 data;
+       u64 qmdata;
        int ret;
 
        ret = netxen_sysfs_validate_crb(adapter, offset, size);
        if (ret != 0)
                return ret;
 
-       memcpy(&data, buf, size);
-       NXWR32(adapter, offset, data);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id) &&
+               ADDR_IN_RANGE(offset, NETXEN_PCI_CAMQM,
+                                       NETXEN_PCI_CAMQM_2M_END)) {
+               memcpy(&qmdata, buf, size);
+               netxen_pci_camqm_write_2M(adapter, offset, qmdata);
+       } else {
+               memcpy(&data, buf, size);
+               NXWR32(adapter, offset, data);
+       }
+
        return size;
 }