aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/mlx4
diff options
context:
space:
mode:
authorYevgeny Petrilin <yevgenyp@mellanox.co.il>2008-10-22 18:38:42 -0400
committerRoland Dreier <rolandd@cisco.com>2008-10-22 18:38:42 -0400
commit7ff93f8b7ecbc36e7ffc5c11a61643821c1bfee5 (patch)
tree4b38e1ead8b27a480cc766f6927dccf5b63793ae /drivers/net/mlx4
parent2a2336f8228292b8197f4187e54b0748903e6645 (diff)
mlx4_core: Multiple port type support
Multi-protocol adapters support different port types. Each consumer of mlx4_core queries for supported port types; in particular mlx4_ib can no longer assume that all physical ports belong to it. Port type is configured through a sysfs interface. When the type of a port is changed, all mlx4 interfaces are unregistered, and then registered again with the new port types. Signed-off-by: Yevgeny Petrilin <yevgenyp@mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/net/mlx4')
-rw-r--r--drivers/net/mlx4/fw.c4
-rw-r--r--drivers/net/mlx4/fw.h1
-rw-r--r--drivers/net/mlx4/main.c211
-rw-r--r--drivers/net/mlx4/mlx4.h6
-rw-r--r--drivers/net/mlx4/port.c23
5 files changed, 239 insertions, 6 deletions
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index 8d402db9a03d..be09fdb79cb8 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -88,6 +88,7 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u32 flags)
88 [ 8] = "P_Key violation counter", 88 [ 8] = "P_Key violation counter",
89 [ 9] = "Q_Key violation counter", 89 [ 9] = "Q_Key violation counter",
90 [10] = "VMM", 90 [10] = "VMM",
91 [12] = "DPDP",
91 [16] = "MW support", 92 [16] = "MW support",
92 [17] = "APM support", 93 [17] = "APM support",
93 [18] = "Atomic ops support", 94 [18] = "Atomic ops support",
@@ -354,6 +355,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
354 dev_cap->max_pkeys[i] = 1 << (field & 0xf); 355 dev_cap->max_pkeys[i] = 1 << (field & 0xf);
355 } 356 }
356 } else { 357 } else {
358#define QUERY_PORT_SUPPORTED_TYPE_OFFSET 0x00
357#define QUERY_PORT_MTU_OFFSET 0x01 359#define QUERY_PORT_MTU_OFFSET 0x01
358#define QUERY_PORT_ETH_MTU_OFFSET 0x02 360#define QUERY_PORT_ETH_MTU_OFFSET 0x02
359#define QUERY_PORT_WIDTH_OFFSET 0x06 361#define QUERY_PORT_WIDTH_OFFSET 0x06
@@ -368,6 +370,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
368 if (err) 370 if (err)
369 goto out; 371 goto out;
370 372
373 MLX4_GET(field, outbox, QUERY_PORT_SUPPORTED_TYPE_OFFSET);
374 dev_cap->supported_port_types[i] = field & 3;
371 MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET); 375 MLX4_GET(field, outbox, QUERY_PORT_MTU_OFFSET);
372 dev_cap->ib_mtu[i] = field & 0xf; 376 dev_cap->ib_mtu[i] = field & 0xf;
373 MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET); 377 MLX4_GET(field, outbox, QUERY_PORT_WIDTH_OFFSET);
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index d0913d4d262a..526d7f30c041 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -104,6 +104,7 @@ struct mlx4_dev_cap {
104 u32 reserved_lkey; 104 u32 reserved_lkey;
105 u64 max_icm_sz; 105 u64 max_icm_sz;
106 int max_gso_sz; 106 int max_gso_sz;
107 u8 supported_port_types[MLX4_MAX_PORTS + 1];
107 u8 log_max_macs[MLX4_MAX_PORTS + 1]; 108 u8 log_max_macs[MLX4_MAX_PORTS + 1];
108 u8 log_max_vlans[MLX4_MAX_PORTS + 1]; 109 u8 log_max_vlans[MLX4_MAX_PORTS + 1];
109}; 110};
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 0a5c8bfb3f1f..c1d447873bf1 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -98,6 +98,44 @@ module_param_named(use_prio, use_prio, bool, 0444);
98MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports " 98MODULE_PARM_DESC(use_prio, "Enable steering by VLAN priority on ETH ports "
99 "(0/1, default 0)"); 99 "(0/1, default 0)");
100 100
101static int mlx4_check_port_params(struct mlx4_dev *dev,
102 enum mlx4_port_type *port_type)
103{
104 int i;
105
106 for (i = 0; i < dev->caps.num_ports - 1; i++) {
107 if (port_type[i] != port_type[i+1] &&
108 !(dev->caps.flags & MLX4_DEV_CAP_FLAG_DPDP)) {
109 mlx4_err(dev, "Only same port types supported "
110 "on this HCA, aborting.\n");
111 return -EINVAL;
112 }
113 }
114 if ((port_type[0] == MLX4_PORT_TYPE_ETH) &&
115 (port_type[1] == MLX4_PORT_TYPE_IB)) {
116 mlx4_err(dev, "eth-ib configuration is not supported.\n");
117 return -EINVAL;
118 }
119
120 for (i = 0; i < dev->caps.num_ports; i++) {
121 if (!(port_type[i] & dev->caps.supported_type[i+1])) {
122 mlx4_err(dev, "Requested port type for port %d is not "
123 "supported on this HCA\n", i + 1);
124 return -EINVAL;
125 }
126 }
127 return 0;
128}
129
130static void mlx4_set_port_mask(struct mlx4_dev *dev)
131{
132 int i;
133
134 dev->caps.port_mask = 0;
135 for (i = 1; i <= dev->caps.num_ports; ++i)
136 if (dev->caps.port_type[i] == MLX4_PORT_TYPE_IB)
137 dev->caps.port_mask |= 1 << (i - 1);
138}
101static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) 139static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
102{ 140{
103 int err; 141 int err;
@@ -139,6 +177,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
139 dev->caps.port_width_cap[i] = dev_cap->max_port_width[i]; 177 dev->caps.port_width_cap[i] = dev_cap->max_port_width[i];
140 dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i]; 178 dev->caps.eth_mtu_cap[i] = dev_cap->eth_mtu[i];
141 dev->caps.def_mac[i] = dev_cap->def_mac[i]; 179 dev->caps.def_mac[i] = dev_cap->def_mac[i];
180 dev->caps.supported_type[i] = dev_cap->supported_port_types[i];
142 } 181 }
143 182
144 dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE; 183 dev->caps.num_uars = dev_cap->uar_size / PAGE_SIZE;
@@ -182,6 +221,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
182 dev->caps.log_num_prios = use_prio ? 3 : 0; 221 dev->caps.log_num_prios = use_prio ? 3 : 0;
183 222
184 for (i = 1; i <= dev->caps.num_ports; ++i) { 223 for (i = 1; i <= dev->caps.num_ports; ++i) {
224 if (dev->caps.supported_type[i] != MLX4_PORT_TYPE_ETH)
225 dev->caps.port_type[i] = MLX4_PORT_TYPE_IB;
226 else
227 dev->caps.port_type[i] = MLX4_PORT_TYPE_ETH;
228
185 if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) { 229 if (dev->caps.log_num_macs > dev_cap->log_max_macs[i]) {
186 dev->caps.log_num_macs = dev_cap->log_max_macs[i]; 230 dev->caps.log_num_macs = dev_cap->log_max_macs[i];
187 mlx4_warn(dev, "Requested number of MACs is too much " 231 mlx4_warn(dev, "Requested number of MACs is too much "
@@ -196,6 +240,8 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
196 } 240 }
197 } 241 }
198 242
243 mlx4_set_port_mask(dev);
244
199 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps; 245 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW] = dev_cap->reserved_qps;
200 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] = 246 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_ETH_ADDR] =
201 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] = 247 dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FC_ADDR] =
@@ -213,6 +259,95 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
213 return 0; 259 return 0;
214} 260}
215 261
262/*
263 * Change the port configuration of the device.
264 * Every user of this function must hold the port mutex.
265 */
266static int mlx4_change_port_types(struct mlx4_dev *dev,
267 enum mlx4_port_type *port_types)
268{
269 int err = 0;
270 int change = 0;
271 int port;
272
273 for (port = 0; port < dev->caps.num_ports; port++) {
274 if (port_types[port] != dev->caps.port_type[port + 1]) {
275 change = 1;
276 dev->caps.port_type[port + 1] = port_types[port];
277 }
278 }
279 if (change) {
280 mlx4_unregister_device(dev);
281 for (port = 1; port <= dev->caps.num_ports; port++) {
282 mlx4_CLOSE_PORT(dev, port);
283 err = mlx4_SET_PORT(dev, port);
284 if (err) {
285 mlx4_err(dev, "Failed to set port %d, "
286 "aborting\n", port);
287 goto out;
288 }
289 }
290 mlx4_set_port_mask(dev);
291 err = mlx4_register_device(dev);
292 }
293
294out:
295 return err;
296}
297
298static ssize_t show_port_type(struct device *dev,
299 struct device_attribute *attr,
300 char *buf)
301{
302 struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
303 port_attr);
304 struct mlx4_dev *mdev = info->dev;
305
306 return sprintf(buf, "%s\n",
307 mdev->caps.port_type[info->port] == MLX4_PORT_TYPE_IB ?
308 "ib" : "eth");
309}
310
311static ssize_t set_port_type(struct device *dev,
312 struct device_attribute *attr,
313 const char *buf, size_t count)
314{
315 struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
316 port_attr);
317 struct mlx4_dev *mdev = info->dev;
318 struct mlx4_priv *priv = mlx4_priv(mdev);
319 enum mlx4_port_type types[MLX4_MAX_PORTS];
320 int i;
321 int err = 0;
322
323 if (!strcmp(buf, "ib\n"))
324 info->tmp_type = MLX4_PORT_TYPE_IB;
325 else if (!strcmp(buf, "eth\n"))
326 info->tmp_type = MLX4_PORT_TYPE_ETH;
327 else {
328 mlx4_err(mdev, "%s is not supported port type\n", buf);
329 return -EINVAL;
330 }
331
332 mutex_lock(&priv->port_mutex);
333 for (i = 0; i < mdev->caps.num_ports; i++)
334 types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type :
335 mdev->caps.port_type[i+1];
336
337 err = mlx4_check_port_params(mdev, types);
338 if (err)
339 goto out;
340
341 for (i = 1; i <= mdev->caps.num_ports; i++)
342 priv->port[i].tmp_type = 0;
343
344 err = mlx4_change_port_types(mdev, types);
345
346out:
347 mutex_unlock(&priv->port_mutex);
348 return err ? err : count;
349}
350
216static int mlx4_load_fw(struct mlx4_dev *dev) 351static int mlx4_load_fw(struct mlx4_dev *dev)
217{ 352{
218 struct mlx4_priv *priv = mlx4_priv(dev); 353 struct mlx4_priv *priv = mlx4_priv(dev);
@@ -617,6 +752,7 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
617{ 752{
618 struct mlx4_priv *priv = mlx4_priv(dev); 753 struct mlx4_priv *priv = mlx4_priv(dev);
619 int err; 754 int err;
755 int port;
620 756
621 err = mlx4_init_uar_table(dev); 757 err = mlx4_init_uar_table(dev);
622 if (err) { 758 if (err) {
@@ -715,8 +851,20 @@ static int mlx4_setup_hca(struct mlx4_dev *dev)
715 goto err_qp_table_free; 851 goto err_qp_table_free;
716 } 852 }
717 853
854 for (port = 1; port <= dev->caps.num_ports; port++) {
855 err = mlx4_SET_PORT(dev, port);
856 if (err) {
857 mlx4_err(dev, "Failed to set port %d, aborting\n",
858 port);
859 goto err_mcg_table_free;
860 }
861 }
862
718 return 0; 863 return 0;
719 864
865err_mcg_table_free:
866 mlx4_cleanup_mcg_table(dev);
867
720err_qp_table_free: 868err_qp_table_free:
721 mlx4_cleanup_qp_table(dev); 869 mlx4_cleanup_qp_table(dev);
722 870
@@ -780,14 +928,37 @@ no_msi:
780 priv->eq_table.eq[i].irq = dev->pdev->irq; 928 priv->eq_table.eq[i].irq = dev->pdev->irq;
781} 929}
782 930
783static void mlx4_init_port_info(struct mlx4_dev *dev, int port) 931static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
784{ 932{
785 struct mlx4_port_info *info = &mlx4_priv(dev)->port[port]; 933 struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
934 int err = 0;
786 935
787 info->dev = dev; 936 info->dev = dev;
788 info->port = port; 937 info->port = port;
789 mlx4_init_mac_table(dev, &info->mac_table); 938 mlx4_init_mac_table(dev, &info->mac_table);
790 mlx4_init_vlan_table(dev, &info->vlan_table); 939 mlx4_init_vlan_table(dev, &info->vlan_table);
940
941 sprintf(info->dev_name, "mlx4_port%d", port);
942 info->port_attr.attr.name = info->dev_name;
943 info->port_attr.attr.mode = S_IRUGO | S_IWUSR;
944 info->port_attr.show = show_port_type;
945 info->port_attr.store = set_port_type;
946
947 err = device_create_file(&dev->pdev->dev, &info->port_attr);
948 if (err) {
949 mlx4_err(dev, "Failed to create file for port %d\n", port);
950 info->port = -1;
951 }
952
953 return err;
954}
955
956static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
957{
958 if (info->port < 0)
959 return;
960
961 device_remove_file(&info->dev->pdev->dev, &info->port_attr);
791} 962}
792 963
793static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) 964static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -870,6 +1041,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
870 INIT_LIST_HEAD(&priv->ctx_list); 1041 INIT_LIST_HEAD(&priv->ctx_list);
871 spin_lock_init(&priv->ctx_lock); 1042 spin_lock_init(&priv->ctx_lock);
872 1043
1044 mutex_init(&priv->port_mutex);
1045
873 INIT_LIST_HEAD(&priv->pgdir_list); 1046 INIT_LIST_HEAD(&priv->pgdir_list);
874 mutex_init(&priv->pgdir_mutex); 1047 mutex_init(&priv->pgdir_mutex);
875 1048
@@ -905,18 +1078,24 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
905 if (err) 1078 if (err)
906 goto err_close; 1079 goto err_close;
907 1080
908 for (port = 1; port <= dev->caps.num_ports; port++) 1081 for (port = 1; port <= dev->caps.num_ports; port++) {
909 mlx4_init_port_info(dev, port); 1082 err = mlx4_init_port_info(dev, port);
1083 if (err)
1084 goto err_port;
1085 }
910 1086
911 err = mlx4_register_device(dev); 1087 err = mlx4_register_device(dev);
912 if (err) 1088 if (err)
913 goto err_cleanup; 1089 goto err_port;
914 1090
915 pci_set_drvdata(pdev, dev); 1091 pci_set_drvdata(pdev, dev);
916 1092
917 return 0; 1093 return 0;
918 1094
919err_cleanup: 1095err_port:
1096 for (port = 1; port <= dev->caps.num_ports; port++)
1097 mlx4_cleanup_port_info(&priv->port[port]);
1098
920 mlx4_cleanup_mcg_table(dev); 1099 mlx4_cleanup_mcg_table(dev);
921 mlx4_cleanup_qp_table(dev); 1100 mlx4_cleanup_qp_table(dev);
922 mlx4_cleanup_srq_table(dev); 1101 mlx4_cleanup_srq_table(dev);
@@ -973,8 +1152,10 @@ static void mlx4_remove_one(struct pci_dev *pdev)
973 if (dev) { 1152 if (dev) {
974 mlx4_unregister_device(dev); 1153 mlx4_unregister_device(dev);
975 1154
976 for (p = 1; p <= dev->caps.num_ports; ++p) 1155 for (p = 1; p <= dev->caps.num_ports; p++) {
1156 mlx4_cleanup_port_info(&priv->port[p]);
977 mlx4_CLOSE_PORT(dev, p); 1157 mlx4_CLOSE_PORT(dev, p);
1158 }
978 1159
979 mlx4_cleanup_mcg_table(dev); 1160 mlx4_cleanup_mcg_table(dev);
980 mlx4_cleanup_qp_table(dev); 1161 mlx4_cleanup_qp_table(dev);
@@ -1026,10 +1207,28 @@ static struct pci_driver mlx4_driver = {
1026 .remove = __devexit_p(mlx4_remove_one) 1207 .remove = __devexit_p(mlx4_remove_one)
1027}; 1208};
1028 1209
1210static int __init mlx4_verify_params(void)
1211{
1212 if ((log_num_mac < 0) || (log_num_mac > 7)) {
1213 printk(KERN_WARNING "mlx4_core: bad num_mac: %d\n", log_num_mac);
1214 return -1;
1215 }
1216
1217 if ((log_num_vlan < 0) || (log_num_vlan > 7)) {
1218 printk(KERN_WARNING "mlx4_core: bad num_vlan: %d\n", log_num_vlan);
1219 return -1;
1220 }
1221
1222 return 0;
1223}
1224
1029static int __init mlx4_init(void) 1225static int __init mlx4_init(void)
1030{ 1226{
1031 int ret; 1227 int ret;
1032 1228
1229 if (mlx4_verify_params())
1230 return -EINVAL;
1231
1033 ret = mlx4_catas_init(); 1232 ret = mlx4_catas_init();
1034 if (ret) 1233 if (ret)
1035 return ret; 1234 return ret;
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 23309f381ee3..fa431fad0eec 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -277,6 +277,9 @@ struct mlx4_vlan_table {
277struct mlx4_port_info { 277struct mlx4_port_info {
278 struct mlx4_dev *dev; 278 struct mlx4_dev *dev;
279 int port; 279 int port;
280 char dev_name[16];
281 struct device_attribute port_attr;
282 enum mlx4_port_type tmp_type;
280 struct mlx4_mac_table mac_table; 283 struct mlx4_mac_table mac_table;
281 struct mlx4_vlan_table vlan_table; 284 struct mlx4_vlan_table vlan_table;
282}; 285};
@@ -310,6 +313,7 @@ struct mlx4_priv {
310 struct mlx4_uar driver_uar; 313 struct mlx4_uar driver_uar;
311 void __iomem *kar; 314 void __iomem *kar;
312 struct mlx4_port_info port[MLX4_MAX_PORTS + 1]; 315 struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
316 struct mutex port_mutex;
313}; 317};
314 318
315static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev) 319static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
@@ -383,4 +387,6 @@ void mlx4_handle_catas_err(struct mlx4_dev *dev);
383void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table); 387void mlx4_init_mac_table(struct mlx4_dev *dev, struct mlx4_mac_table *table);
384void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table); 388void mlx4_init_vlan_table(struct mlx4_dev *dev, struct mlx4_vlan_table *table);
385 389
390int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port);
391
386#endif /* MLX4_H */ 392#endif /* MLX4_H */
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index 8644f3d978ee..e2fdab42c4ce 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -257,3 +257,26 @@ out:
257 mutex_unlock(&table->mutex); 257 mutex_unlock(&table->mutex);
258} 258}
259EXPORT_SYMBOL_GPL(mlx4_unregister_vlan); 259EXPORT_SYMBOL_GPL(mlx4_unregister_vlan);
260
261int mlx4_SET_PORT(struct mlx4_dev *dev, u8 port)
262{
263 struct mlx4_cmd_mailbox *mailbox;
264 int err;
265 u8 is_eth = dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH;
266
267 mailbox = mlx4_alloc_cmd_mailbox(dev);
268 if (IS_ERR(mailbox))
269 return PTR_ERR(mailbox);
270
271 memset(mailbox->buf, 0, 256);
272 if (is_eth) {
273 ((u8 *) mailbox->buf)[3] = 6;
274 ((__be16 *) mailbox->buf)[4] = cpu_to_be16(1 << 15);
275 ((__be16 *) mailbox->buf)[6] = cpu_to_be16(1 << 15);
276 }
277 err = mlx4_cmd(dev, mailbox->dma, port, is_eth, MLX4_CMD_SET_PORT,
278 MLX4_CMD_TIME_CLASS_B);
279
280 mlx4_free_cmd_mailbox(dev, mailbox);
281 return err;
282}