~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise-security

« back to all changes in this revision

Viewing changes to drivers/net/enic/enic_res.c

  • Committer: Package Import Robot
  • Author(s): Paolo Pisati, Paolo Pisati
  • Date: 2011-12-06 15:56:07 UTC
  • Revision ID: package-import@ubuntu.com-20111206155607-pcf44kv5fmhk564f
Tags: 3.2.0-1401.1
[ Paolo Pisati ]

* Rebased on top of Ubuntu-3.2.0-3.8
* Tilt-tracking @ ef2487af4bb15bdd0689631774b5a5e3a59f74e2
* Delete debian.ti-omap4/control, it shoudln't be tracked
* Fix architecture spelling (s/armel/armhf/)
* [Config] Update configs following 3.2 import
* [Config] Fix compilation: disable CODA and ARCH_OMAP3
* [Config] Fix compilation: disable Ethernet Faraday
* Update series to precise

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright 2008-2010 Cisco Systems, Inc.  All rights reserved.
3
 
 * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
4
 
 *
5
 
 * This program is free software; you may redistribute it and/or modify
6
 
 * it under the terms of the GNU General Public License as published by
7
 
 * the Free Software Foundation; version 2 of the License.
8
 
 *
9
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
10
 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
11
 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12
 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
13
 
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
14
 
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
15
 
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
16
 
 * SOFTWARE.
17
 
 *
18
 
 */
19
 
 
20
 
#include <linux/kernel.h>
21
 
#include <linux/errno.h>
22
 
#include <linux/types.h>
23
 
#include <linux/pci.h>
24
 
#include <linux/netdevice.h>
25
 
 
26
 
#include "wq_enet_desc.h"
27
 
#include "rq_enet_desc.h"
28
 
#include "cq_enet_desc.h"
29
 
#include "vnic_resource.h"
30
 
#include "vnic_enet.h"
31
 
#include "vnic_dev.h"
32
 
#include "vnic_wq.h"
33
 
#include "vnic_rq.h"
34
 
#include "vnic_cq.h"
35
 
#include "vnic_intr.h"
36
 
#include "vnic_stats.h"
37
 
#include "vnic_nic.h"
38
 
#include "vnic_rss.h"
39
 
#include "enic_res.h"
40
 
#include "enic.h"
41
 
 
42
 
int enic_get_vnic_config(struct enic *enic)
43
 
{
44
 
        struct vnic_enet_config *c = &enic->config;
45
 
        int err;
46
 
 
47
 
        err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
48
 
        if (err) {
49
 
                dev_err(enic_get_dev(enic),
50
 
                        "Error getting MAC addr, %d\n", err);
51
 
                return err;
52
 
        }
53
 
 
54
 
#define GET_CONFIG(m) \
55
 
        do { \
56
 
                err = vnic_dev_spec(enic->vdev, \
57
 
                        offsetof(struct vnic_enet_config, m), \
58
 
                        sizeof(c->m), &c->m); \
59
 
                if (err) { \
60
 
                        dev_err(enic_get_dev(enic), \
61
 
                                "Error getting %s, %d\n", #m, err); \
62
 
                        return err; \
63
 
                } \
64
 
        } while (0)
65
 
 
66
 
        GET_CONFIG(flags);
67
 
        GET_CONFIG(wq_desc_count);
68
 
        GET_CONFIG(rq_desc_count);
69
 
        GET_CONFIG(mtu);
70
 
        GET_CONFIG(intr_timer_type);
71
 
        GET_CONFIG(intr_mode);
72
 
        GET_CONFIG(intr_timer_usec);
73
 
        GET_CONFIG(loop_tag);
74
 
 
75
 
        c->wq_desc_count =
76
 
                min_t(u32, ENIC_MAX_WQ_DESCS,
77
 
                max_t(u32, ENIC_MIN_WQ_DESCS,
78
 
                c->wq_desc_count));
79
 
        c->wq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
80
 
 
81
 
        c->rq_desc_count =
82
 
                min_t(u32, ENIC_MAX_RQ_DESCS,
83
 
                max_t(u32, ENIC_MIN_RQ_DESCS,
84
 
                c->rq_desc_count));
85
 
        c->rq_desc_count &= 0xffffffe0; /* must be aligned to groups of 32 */
86
 
 
87
 
        if (c->mtu == 0)
88
 
                c->mtu = 1500;
89
 
        c->mtu = min_t(u16, ENIC_MAX_MTU,
90
 
                max_t(u16, ENIC_MIN_MTU,
91
 
                c->mtu));
92
 
 
93
 
        c->intr_timer_usec = min_t(u32,
94
 
                INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
95
 
                c->intr_timer_usec);
96
 
 
97
 
        dev_info(enic_get_dev(enic),
98
 
                "vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
99
 
                enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
100
 
        dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d "
101
 
                "tso %d intr timer %d usec rss %d\n",
102
 
                ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM),
103
 
                ENIC_SETTING(enic, TSO),
104
 
                c->intr_timer_usec, ENIC_SETTING(enic, RSS));
105
 
 
106
 
        return 0;
107
 
}
108
 
 
109
 
int enic_add_vlan(struct enic *enic, u16 vlanid)
110
 
{
111
 
        u64 a0 = vlanid, a1 = 0;
112
 
        int wait = 1000;
113
 
        int err;
114
 
 
115
 
        err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
116
 
        if (err)
117
 
                dev_err(enic_get_dev(enic), "Can't add vlan id, %d\n", err);
118
 
 
119
 
        return err;
120
 
}
121
 
 
122
 
int enic_del_vlan(struct enic *enic, u16 vlanid)
123
 
{
124
 
        u64 a0 = vlanid, a1 = 0;
125
 
        int wait = 1000;
126
 
        int err;
127
 
 
128
 
        err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
129
 
        if (err)
130
 
                dev_err(enic_get_dev(enic), "Can't delete vlan id, %d\n", err);
131
 
 
132
 
        return err;
133
 
}
134
 
 
135
 
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
136
 
        u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
137
 
        u8 ig_vlan_strip_en)
138
 
{
139
 
        u64 a0, a1;
140
 
        u32 nic_cfg;
141
 
        int wait = 1000;
142
 
 
143
 
        vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
144
 
                rss_hash_type, rss_hash_bits, rss_base_cpu,
145
 
                rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
146
 
 
147
 
        a0 = nic_cfg;
148
 
        a1 = 0;
149
 
 
150
 
        return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
151
 
}
152
 
 
153
 
int enic_set_rss_key(struct enic *enic, dma_addr_t key_pa, u64 len)
154
 
{
155
 
        u64 a0 = (u64)key_pa, a1 = len;
156
 
        int wait = 1000;
157
 
 
158
 
        return vnic_dev_cmd(enic->vdev, CMD_RSS_KEY, &a0, &a1, wait);
159
 
}
160
 
 
161
 
int enic_set_rss_cpu(struct enic *enic, dma_addr_t cpu_pa, u64 len)
162
 
{
163
 
        u64 a0 = (u64)cpu_pa, a1 = len;
164
 
        int wait = 1000;
165
 
 
166
 
        return vnic_dev_cmd(enic->vdev, CMD_RSS_CPU, &a0, &a1, wait);
167
 
}
168
 
 
169
 
void enic_free_vnic_resources(struct enic *enic)
170
 
{
171
 
        unsigned int i;
172
 
 
173
 
        for (i = 0; i < enic->wq_count; i++)
174
 
                vnic_wq_free(&enic->wq[i]);
175
 
        for (i = 0; i < enic->rq_count; i++)
176
 
                vnic_rq_free(&enic->rq[i]);
177
 
        for (i = 0; i < enic->cq_count; i++)
178
 
                vnic_cq_free(&enic->cq[i]);
179
 
        for (i = 0; i < enic->intr_count; i++)
180
 
                vnic_intr_free(&enic->intr[i]);
181
 
}
182
 
 
183
 
void enic_get_res_counts(struct enic *enic)
184
 
{
185
 
        enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
186
 
        enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
187
 
        enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
188
 
        enic->intr_count = vnic_dev_get_res_count(enic->vdev,
189
 
                RES_TYPE_INTR_CTRL);
190
 
 
191
 
        dev_info(enic_get_dev(enic),
192
 
                "vNIC resources avail: wq %d rq %d cq %d intr %d\n",
193
 
                enic->wq_count, enic->rq_count,
194
 
                enic->cq_count, enic->intr_count);
195
 
}
196
 
 
197
 
void enic_init_vnic_resources(struct enic *enic)
198
 
{
199
 
        enum vnic_dev_intr_mode intr_mode;
200
 
        unsigned int mask_on_assertion;
201
 
        unsigned int interrupt_offset;
202
 
        unsigned int error_interrupt_enable;
203
 
        unsigned int error_interrupt_offset;
204
 
        unsigned int cq_index;
205
 
        unsigned int i;
206
 
 
207
 
        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
208
 
 
209
 
        /* Init RQ/WQ resources.
210
 
         *
211
 
         * RQ[0 - n-1] point to CQ[0 - n-1]
212
 
         * WQ[0 - m-1] point to CQ[n - n+m-1]
213
 
         *
214
 
         * Error interrupt is not enabled for MSI.
215
 
         */
216
 
 
217
 
        switch (intr_mode) {
218
 
        case VNIC_DEV_INTR_MODE_INTX:
219
 
        case VNIC_DEV_INTR_MODE_MSIX:
220
 
                error_interrupt_enable = 1;
221
 
                error_interrupt_offset = enic->intr_count - 2;
222
 
                break;
223
 
        default:
224
 
                error_interrupt_enable = 0;
225
 
                error_interrupt_offset = 0;
226
 
                break;
227
 
        }
228
 
 
229
 
        for (i = 0; i < enic->rq_count; i++) {
230
 
                cq_index = i;
231
 
                vnic_rq_init(&enic->rq[i],
232
 
                        cq_index,
233
 
                        error_interrupt_enable,
234
 
                        error_interrupt_offset);
235
 
        }
236
 
 
237
 
        for (i = 0; i < enic->wq_count; i++) {
238
 
                cq_index = enic->rq_count + i;
239
 
                vnic_wq_init(&enic->wq[i],
240
 
                        cq_index,
241
 
                        error_interrupt_enable,
242
 
                        error_interrupt_offset);
243
 
        }
244
 
 
245
 
        /* Init CQ resources
246
 
         *
247
 
         * CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
248
 
         * CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
249
 
         */
250
 
 
251
 
        for (i = 0; i < enic->cq_count; i++) {
252
 
 
253
 
                switch (intr_mode) {
254
 
                case VNIC_DEV_INTR_MODE_MSIX:
255
 
                        interrupt_offset = i;
256
 
                        break;
257
 
                default:
258
 
                        interrupt_offset = 0;
259
 
                        break;
260
 
                }
261
 
 
262
 
                vnic_cq_init(&enic->cq[i],
263
 
                        0 /* flow_control_enable */,
264
 
                        1 /* color_enable */,
265
 
                        0 /* cq_head */,
266
 
                        0 /* cq_tail */,
267
 
                        1 /* cq_tail_color */,
268
 
                        1 /* interrupt_enable */,
269
 
                        1 /* cq_entry_enable */,
270
 
                        0 /* cq_message_enable */,
271
 
                        interrupt_offset,
272
 
                        0 /* cq_message_addr */);
273
 
        }
274
 
 
275
 
        /* Init INTR resources
276
 
         *
277
 
         * mask_on_assertion is not used for INTx due to the level-
278
 
         * triggered nature of INTx
279
 
         */
280
 
 
281
 
        switch (intr_mode) {
282
 
        case VNIC_DEV_INTR_MODE_MSI:
283
 
        case VNIC_DEV_INTR_MODE_MSIX:
284
 
                mask_on_assertion = 1;
285
 
                break;
286
 
        default:
287
 
                mask_on_assertion = 0;
288
 
                break;
289
 
        }
290
 
 
291
 
        for (i = 0; i < enic->intr_count; i++) {
292
 
                vnic_intr_init(&enic->intr[i],
293
 
                        INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
294
 
                        enic->config.intr_timer_type,
295
 
                        mask_on_assertion);
296
 
        }
297
 
}
298
 
 
299
 
int enic_alloc_vnic_resources(struct enic *enic)
300
 
{
301
 
        enum vnic_dev_intr_mode intr_mode;
302
 
        unsigned int i;
303
 
        int err;
304
 
 
305
 
        intr_mode = vnic_dev_get_intr_mode(enic->vdev);
306
 
 
307
 
        dev_info(enic_get_dev(enic), "vNIC resources used:  "
308
 
                "wq %d rq %d cq %d intr %d intr mode %s\n",
309
 
                enic->wq_count, enic->rq_count,
310
 
                enic->cq_count, enic->intr_count,
311
 
                intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
312
 
                intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
313
 
                intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
314
 
                "unknown");
315
 
 
316
 
        /* Allocate queue resources
317
 
         */
318
 
 
319
 
        for (i = 0; i < enic->wq_count; i++) {
320
 
                err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
321
 
                        enic->config.wq_desc_count,
322
 
                        sizeof(struct wq_enet_desc));
323
 
                if (err)
324
 
                        goto err_out_cleanup;
325
 
        }
326
 
 
327
 
        for (i = 0; i < enic->rq_count; i++) {
328
 
                err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
329
 
                        enic->config.rq_desc_count,
330
 
                        sizeof(struct rq_enet_desc));
331
 
                if (err)
332
 
                        goto err_out_cleanup;
333
 
        }
334
 
 
335
 
        for (i = 0; i < enic->cq_count; i++) {
336
 
                if (i < enic->rq_count)
337
 
                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
338
 
                                enic->config.rq_desc_count,
339
 
                                sizeof(struct cq_enet_rq_desc));
340
 
                else
341
 
                        err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
342
 
                                enic->config.wq_desc_count,
343
 
                                sizeof(struct cq_enet_wq_desc));
344
 
                if (err)
345
 
                        goto err_out_cleanup;
346
 
        }
347
 
 
348
 
        for (i = 0; i < enic->intr_count; i++) {
349
 
                err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
350
 
                if (err)
351
 
                        goto err_out_cleanup;
352
 
        }
353
 
 
354
 
        /* Hook remaining resource
355
 
         */
356
 
 
357
 
        enic->legacy_pba = vnic_dev_get_res(enic->vdev,
358
 
                RES_TYPE_INTR_PBA_LEGACY, 0);
359
 
        if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
360
 
                dev_err(enic_get_dev(enic),
361
 
                        "Failed to hook legacy pba resource\n");
362
 
                err = -ENODEV;
363
 
                goto err_out_cleanup;
364
 
        }
365
 
 
366
 
        return 0;
367
 
 
368
 
err_out_cleanup:
369
 
        enic_free_vnic_resources(enic);
370
 
 
371
 
        return err;
372
 
}