diff options
author | Scott Feldman <scofeldm@cisco.com> | 2009-09-03 13:01:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-09-03 23:19:09 -0400 |
commit | 27e6c7d33835e7f347cdfb5025766b7d9a6596d1 (patch) | |
tree | 70ba8cc0b46da5e7035d2bd230869d5d716c9e9b | |
parent | 1a123a3168566b10f87f228ae963770b26f27420 (diff) |
enic: add support for multiple BARs
Nic firmware can place resources (queues, intrs, etc) on multiple BARs, so
allow driver to discover/map resources beyond BAR0.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/enic/enic.h | 8 | ||||
-rw-r--r-- | drivers/net/enic/enic_main.c | 48 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.c | 41 | ||||
-rw-r--r-- | drivers/net/enic/vnic_dev.h | 5 |
4 files changed, 66 insertions, 36 deletions
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index c26cea0b300e..cfe94b2e03af 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h | |||
@@ -33,13 +33,15 @@ | |||
33 | 33 | ||
34 | #define DRV_NAME "enic" | 34 | #define DRV_NAME "enic" |
35 | #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" | 35 | #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" |
36 | #define DRV_VERSION "1.0.0.933" | 36 | #define DRV_VERSION "1.1.0.100" |
37 | #define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" | 37 | #define DRV_COPYRIGHT "Copyright 2008-2009 Cisco Systems, Inc" |
38 | #define PFX DRV_NAME ": " | 38 | #define PFX DRV_NAME ": " |
39 | 39 | ||
40 | #define ENIC_LRO_MAX_DESC 8 | 40 | #define ENIC_LRO_MAX_DESC 8 |
41 | #define ENIC_LRO_MAX_AGGR 64 | 41 | #define ENIC_LRO_MAX_AGGR 64 |
42 | 42 | ||
43 | #define ENIC_BARS_MAX 6 | ||
44 | |||
43 | enum enic_cq_index { | 45 | enum enic_cq_index { |
44 | ENIC_CQ_RQ, | 46 | ENIC_CQ_RQ, |
45 | ENIC_CQ_WQ, | 47 | ENIC_CQ_WQ, |
@@ -73,7 +75,7 @@ struct enic { | |||
73 | struct net_device *netdev; | 75 | struct net_device *netdev; |
74 | struct pci_dev *pdev; | 76 | struct pci_dev *pdev; |
75 | struct vnic_enet_config config; | 77 | struct vnic_enet_config config; |
76 | struct vnic_dev_bar bar0; | 78 | struct vnic_dev_bar bar[ENIC_BARS_MAX]; |
77 | struct vnic_dev *vdev; | 79 | struct vnic_dev *vdev; |
78 | struct timer_list notify_timer; | 80 | struct timer_list notify_timer; |
79 | struct work_struct reset; | 81 | struct work_struct reset; |
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2ea036333db2..2821a1db547d 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c | |||
@@ -1609,12 +1609,6 @@ static void enic_clear_intr_mode(struct enic *enic) | |||
1609 | vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); | 1609 | vnic_dev_set_intr_mode(enic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); |
1610 | } | 1610 | } |
1611 | 1611 | ||
1612 | static void enic_iounmap(struct enic *enic) | ||
1613 | { | ||
1614 | if (enic->bar0.vaddr) | ||
1615 | iounmap(enic->bar0.vaddr); | ||
1616 | } | ||
1617 | |||
1618 | static const struct net_device_ops enic_netdev_ops = { | 1612 | static const struct net_device_ops enic_netdev_ops = { |
1619 | .ndo_open = enic_open, | 1613 | .ndo_open = enic_open, |
1620 | .ndo_stop = enic_stop, | 1614 | .ndo_stop = enic_stop, |
@@ -1633,6 +1627,15 @@ static const struct net_device_ops enic_netdev_ops = { | |||
1633 | #endif | 1627 | #endif |
1634 | }; | 1628 | }; |
1635 | 1629 | ||
1630 | static void enic_iounmap(struct enic *enic) | ||
1631 | { | ||
1632 | unsigned int i; | ||
1633 | |||
1634 | for (i = 0; i < ARRAY_SIZE(enic->bar); i++) | ||
1635 | if (enic->bar[i].vaddr) | ||
1636 | iounmap(enic->bar[i].vaddr); | ||
1637 | } | ||
1638 | |||
1636 | static int __devinit enic_probe(struct pci_dev *pdev, | 1639 | static int __devinit enic_probe(struct pci_dev *pdev, |
1637 | const struct pci_device_id *ent) | 1640 | const struct pci_device_id *ent) |
1638 | { | 1641 | { |
@@ -1710,31 +1713,28 @@ static int __devinit enic_probe(struct pci_dev *pdev, | |||
1710 | using_dac = 1; | 1713 | using_dac = 1; |
1711 | } | 1714 | } |
1712 | 1715 | ||
1713 | /* Map vNIC resources from BAR0 | 1716 | /* Map vNIC resources from BAR0-5 |
1714 | */ | 1717 | */ |
1715 | 1718 | ||
1716 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { | 1719 | for (i = 0; i < ARRAY_SIZE(enic->bar); i++) { |
1717 | printk(KERN_ERR PFX | 1720 | if (!(pci_resource_flags(pdev, i) & IORESOURCE_MEM)) |
1718 | "BAR0 not memory-map'able, aborting.\n"); | 1721 | continue; |
1719 | err = -ENODEV; | 1722 | enic->bar[i].len = pci_resource_len(pdev, i); |
1720 | goto err_out_release_regions; | 1723 | enic->bar[i].vaddr = pci_iomap(pdev, i, enic->bar[i].len); |
1721 | } | 1724 | if (!enic->bar[i].vaddr) { |
1722 | 1725 | printk(KERN_ERR PFX | |
1723 | enic->bar0.vaddr = pci_iomap(pdev, 0, enic->bar0.len); | 1726 | "Cannot memory-map BAR %d, aborting.\n", i); |
1724 | enic->bar0.bus_addr = pci_resource_start(pdev, 0); | 1727 | err = -ENODEV; |
1725 | enic->bar0.len = pci_resource_len(pdev, 0); | 1728 | goto err_out_iounmap; |
1726 | 1729 | } | |
1727 | if (!enic->bar0.vaddr) { | 1730 | enic->bar[i].bus_addr = pci_resource_start(pdev, i); |
1728 | printk(KERN_ERR PFX | ||
1729 | "Cannot memory-map BAR0 res hdr, aborting.\n"); | ||
1730 | err = -ENODEV; | ||
1731 | goto err_out_release_regions; | ||
1732 | } | 1731 | } |
1733 | 1732 | ||
1734 | /* Register vNIC device | 1733 | /* Register vNIC device |
1735 | */ | 1734 | */ |
1736 | 1735 | ||
1737 | enic->vdev = vnic_dev_register(NULL, enic, pdev, &enic->bar0); | 1736 | enic->vdev = vnic_dev_register(NULL, enic, pdev, enic->bar, |
1737 | ARRAY_SIZE(enic->bar)); | ||
1738 | if (!enic->vdev) { | 1738 | if (!enic->vdev) { |
1739 | printk(KERN_ERR PFX | 1739 | printk(KERN_ERR PFX |
1740 | "vNIC registration failed, aborting.\n"); | 1740 | "vNIC registration failed, aborting.\n"); |
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index e21b9d636aec..d5c28efedd98 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | struct vnic_res { | 32 | struct vnic_res { |
33 | void __iomem *vaddr; | 33 | void __iomem *vaddr; |
34 | dma_addr_t bus_addr; | ||
34 | unsigned int count; | 35 | unsigned int count; |
35 | }; | 36 | }; |
36 | 37 | ||
@@ -67,12 +68,15 @@ void *vnic_dev_priv(struct vnic_dev *vdev) | |||
67 | } | 68 | } |
68 | 69 | ||
69 | static int vnic_dev_discover_res(struct vnic_dev *vdev, | 70 | static int vnic_dev_discover_res(struct vnic_dev *vdev, |
70 | struct vnic_dev_bar *bar) | 71 | struct vnic_dev_bar *bar, unsigned int num_bars) |
71 | { | 72 | { |
72 | struct vnic_resource_header __iomem *rh; | 73 | struct vnic_resource_header __iomem *rh; |
73 | struct vnic_resource __iomem *r; | 74 | struct vnic_resource __iomem *r; |
74 | u8 type; | 75 | u8 type; |
75 | 76 | ||
77 | if (num_bars == 0) | ||
78 | return -EINVAL; | ||
79 | |||
76 | if (bar->len < VNIC_MAX_RES_HDR_SIZE) { | 80 | if (bar->len < VNIC_MAX_RES_HDR_SIZE) { |
77 | printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); | 81 | printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); |
78 | return -EINVAL; | 82 | return -EINVAL; |
@@ -104,7 +108,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, | |||
104 | 108 | ||
105 | r++; | 109 | r++; |
106 | 110 | ||
107 | if (bar_num != 0) /* only mapping in BAR0 resources */ | 111 | if (bar_num >= num_bars) |
112 | continue; | ||
113 | |||
114 | if (!bar[bar_num].len || !bar[bar_num].vaddr) | ||
108 | continue; | 115 | continue; |
109 | 116 | ||
110 | switch (type) { | 117 | switch (type) { |
@@ -114,13 +121,13 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, | |||
114 | case RES_TYPE_INTR_CTRL: | 121 | case RES_TYPE_INTR_CTRL: |
115 | /* each count is stride bytes long */ | 122 | /* each count is stride bytes long */ |
116 | len = count * VNIC_RES_STRIDE; | 123 | len = count * VNIC_RES_STRIDE; |
117 | if (len + bar_offset > bar->len) { | 124 | if (len + bar_offset > bar[bar_num].len) { |
118 | printk(KERN_ERR "vNIC BAR0 resource %d " | 125 | printk(KERN_ERR "vNIC BAR0 resource %d " |
119 | "out-of-bounds, offset 0x%x + " | 126 | "out-of-bounds, offset 0x%x + " |
120 | "size 0x%x > bar len 0x%lx\n", | 127 | "size 0x%x > bar len 0x%lx\n", |
121 | type, bar_offset, | 128 | type, bar_offset, |
122 | len, | 129 | len, |
123 | bar->len); | 130 | bar[bar_num].len); |
124 | return -EINVAL; | 131 | return -EINVAL; |
125 | } | 132 | } |
126 | break; | 133 | break; |
@@ -133,7 +140,9 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, | |||
133 | } | 140 | } |
134 | 141 | ||
135 | vdev->res[type].count = count; | 142 | vdev->res[type].count = count; |
136 | vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; | 143 | vdev->res[type].vaddr = (char __iomem *)bar[bar_num].vaddr + |
144 | bar_offset; | ||
145 | vdev->res[type].bus_addr = bar[bar_num].bus_addr + bar_offset; | ||
137 | } | 146 | } |
138 | 147 | ||
139 | return 0; | 148 | return 0; |
@@ -163,6 +172,21 @@ void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, | |||
163 | } | 172 | } |
164 | } | 173 | } |
165 | 174 | ||
175 | dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, | ||
176 | enum vnic_res_type type, unsigned int index) | ||
177 | { | ||
178 | switch (type) { | ||
179 | case RES_TYPE_WQ: | ||
180 | case RES_TYPE_RQ: | ||
181 | case RES_TYPE_CQ: | ||
182 | case RES_TYPE_INTR_CTRL: | ||
183 | return vdev->res[type].bus_addr + | ||
184 | index * VNIC_RES_STRIDE; | ||
185 | default: | ||
186 | return vdev->res[type].bus_addr; | ||
187 | } | ||
188 | } | ||
189 | |||
166 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, | 190 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, |
167 | unsigned int desc_count, unsigned int desc_size) | 191 | unsigned int desc_count, unsigned int desc_size) |
168 | { | 192 | { |
@@ -257,7 +281,7 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | |||
257 | iowrite32(cmd, &devcmd->cmd); | 281 | iowrite32(cmd, &devcmd->cmd); |
258 | 282 | ||
259 | if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) | 283 | if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) |
260 | return 0; | 284 | return 0; |
261 | 285 | ||
262 | for (delay = 0; delay < wait; delay++) { | 286 | for (delay = 0; delay < wait; delay++) { |
263 | 287 | ||
@@ -684,7 +708,8 @@ void vnic_dev_unregister(struct vnic_dev *vdev) | |||
684 | } | 708 | } |
685 | 709 | ||
686 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, | 710 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, |
687 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) | 711 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, |
712 | unsigned int num_bars) | ||
688 | { | 713 | { |
689 | if (!vdev) { | 714 | if (!vdev) { |
690 | vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); | 715 | vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC); |
@@ -695,7 +720,7 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, | |||
695 | vdev->priv = priv; | 720 | vdev->priv = priv; |
696 | vdev->pdev = pdev; | 721 | vdev->pdev = pdev; |
697 | 722 | ||
698 | if (vnic_dev_discover_res(vdev, bar)) | 723 | if (vnic_dev_discover_res(vdev, bar, num_bars)) |
699 | goto err_out; | 724 | goto err_out; |
700 | 725 | ||
701 | vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); | 726 | vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); |
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h index 8aa8db2fd03f..d960edb8cdf5 100644 --- a/drivers/net/enic/vnic_dev.h +++ b/drivers/net/enic/vnic_dev.h | |||
@@ -75,6 +75,8 @@ unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, | |||
75 | enum vnic_res_type type); | 75 | enum vnic_res_type type); |
76 | void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, | 76 | void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, |
77 | unsigned int index); | 77 | unsigned int index); |
78 | dma_addr_t vnic_dev_get_res_bus_addr(struct vnic_dev *vdev, | ||
79 | enum vnic_res_type type, unsigned int index); | ||
78 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, | 80 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, |
79 | unsigned int desc_count, unsigned int desc_size); | 81 | unsigned int desc_count, unsigned int desc_size); |
80 | void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); | 82 | void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); |
@@ -117,6 +119,7 @@ void vnic_dev_set_intr_mode(struct vnic_dev *vdev, | |||
117 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); | 119 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); |
118 | void vnic_dev_unregister(struct vnic_dev *vdev); | 120 | void vnic_dev_unregister(struct vnic_dev *vdev); |
119 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, | 121 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, |
120 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar); | 122 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar, |
123 | unsigned int num_bars); | ||
121 | 124 | ||
122 | #endif /* _VNIC_DEV_H_ */ | 125 | #endif /* _VNIC_DEV_H_ */ |