~ubuntu-branches/ubuntu/trusty/linux-armadaxp/trusty

« back to all changes in this revision

Viewing changes to drivers/pci/ats.c

  • Committer: Package Import Robot
  • Author(s): Michael Casadevall, Bryan Wu, Dann Frazier, Michael Casadeall
  • Date: 2012-03-10 15:00:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120310150054-flugb39zon8vvgwe
Tags: 3.2.0-1600.1
[ Bryan Wu ]
* UBUNTU: import debian/debian.env and debian.armadaxp

[ Dann Frazier ]
* ARM: Armada XP: remove trailing '/' in dirnames in mvRules.mk

[ Michael Casadeall ]
* tools: add some tools for Marvell Armada XP processor
* kernel: timer tick hacking from Marvell
* kernel: Sheeva Errata: add delay on Sheeva when powering down
* net: add Marvell NFP netfilter
* net: socket and skb modifications made by Marvell
* miscdevice: add minor IDs for some Marvell Armada drivers
* fs: introduce memory pool for splice()
* video: EDID detection updates from Marvell Armada XP patchset
* video: backlight: add Marvell Dove LCD backlight driver
* video: display: add THS8200 display driver
* video: framebuffer: add Marvell Dove and Armada XP processor onchip LCD controller driver
* usbtest: add Interrupt transfer testing by Marvell Armada XP code
* usb: ehci: add support for Marvell EHCI controler
* tty/serial: 8250: add support for Marvell Armada XP processor and DeviceTree work
* rtc: add support for Marvell Armada XP onchip RTC controller
* net: pppoe: add Marvell ethernet NFP hook in PPPoE networking driver
* mtd: nand: add support for Marvell Armada XP Nand Flash Controller
* mtd: maps: add Marvell Armada XP specific map driver
* mmc: add support for Marvell Armada XP MMC/SD host controller
* i2c: add support for Marvell Armada XP onchip i2c bus controller
* hwmon: add Kconfig option for Armada XP onchip thermal sensor driver
* dmaengine: add Net DMA support for splice and update Marvell XOR DMA engine driver
* ata: add support for Marvell Armada XP SATA controller and update some quirks
* ARM: add Marvell Armada XP machine to mach-types
* ARM: oprofile: add support for Marvell PJ4B core
* ARM: mm: more ARMv6 switches for Marvell Armada XP
* ARM: remove static declaration to allow compilation
* ARM: alignment access fault trick
* ARM: mm: skip some fault fixing when run on NONE SMP ARMv6 mode during early abort event
* ARM: mm: add Marvell Sheeva CPU Architecture for PJ4B
* ARM: introduce optimized copy operation for Marvell Armada XP
* ARM: SAUCE: hardware breakpoint trick for Marvell Armada XP
* ARM: big endian and little endian tricks for Marvell Armada XP
* ARM: SAUCE: Add Marvell Armada XP build rules to arch/arm/kernel/Makefile
* ARM: vfp: add special handling for Marvell Armada XP
* ARM: add support for Marvell U-Boot
* ARM: add mv_controller_num for ARM PCI drivers
* ARM: add support for local PMUs, general SMP tweaks and cache flushing
* ARM: add Marvell device identifies in glue-proc.h
* ARM: add IPC driver support for Marvell platforms
* ARM: add DMA mapping for Marvell platforms
* ARM: add Sheeva errata and PJ4B code for booting
* ARM: update Kconfig and Makefile to include Marvell Armada XP platforms
* ARM: Armada XP: import LSP from Marvell for Armada XP 3.2 kernel enablement

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * drivers/pci/ats.c
 
3
 *
 
4
 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
 
5
 * Copyright (C) 2011 Advanced Micro Devices,
 
6
 *
 
7
 * PCI Express I/O Virtualization (IOV) support.
 
8
 *   Address Translation Service 1.0
 
9
 *   Page Request Interface added by Joerg Roedel <joerg.roedel@amd.com>
 
10
 *   PASID support added by Joerg Roedel <joerg.roedel@amd.com>
 
11
 */
 
12
 
 
13
#include <linux/export.h>
 
14
#include <linux/pci-ats.h>
 
15
#include <linux/pci.h>
 
16
#include <linux/slab.h>
 
17
 
 
18
#include "pci.h"
 
19
 
 
20
static int ats_alloc_one(struct pci_dev *dev, int ps)
 
21
{
 
22
        int pos;
 
23
        u16 cap;
 
24
        struct pci_ats *ats;
 
25
 
 
26
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
 
27
        if (!pos)
 
28
                return -ENODEV;
 
29
 
 
30
        ats = kzalloc(sizeof(*ats), GFP_KERNEL);
 
31
        if (!ats)
 
32
                return -ENOMEM;
 
33
 
 
34
        ats->pos = pos;
 
35
        ats->stu = ps;
 
36
        pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
 
37
        ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
 
38
                                            PCI_ATS_MAX_QDEP;
 
39
        dev->ats = ats;
 
40
 
 
41
        return 0;
 
42
}
 
43
 
 
44
static void ats_free_one(struct pci_dev *dev)
 
45
{
 
46
        kfree(dev->ats);
 
47
        dev->ats = NULL;
 
48
}
 
49
 
 
50
/**
 
51
 * pci_enable_ats - enable the ATS capability
 
52
 * @dev: the PCI device
 
53
 * @ps: the IOMMU page shift
 
54
 *
 
55
 * Returns 0 on success, or negative on failure.
 
56
 */
 
57
int pci_enable_ats(struct pci_dev *dev, int ps)
 
58
{
 
59
        int rc;
 
60
        u16 ctrl;
 
61
 
 
62
        BUG_ON(dev->ats && dev->ats->is_enabled);
 
63
 
 
64
        if (ps < PCI_ATS_MIN_STU)
 
65
                return -EINVAL;
 
66
 
 
67
        if (dev->is_physfn || dev->is_virtfn) {
 
68
                struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
 
69
 
 
70
                mutex_lock(&pdev->sriov->lock);
 
71
                if (pdev->ats)
 
72
                        rc = pdev->ats->stu == ps ? 0 : -EINVAL;
 
73
                else
 
74
                        rc = ats_alloc_one(pdev, ps);
 
75
 
 
76
                if (!rc)
 
77
                        pdev->ats->ref_cnt++;
 
78
                mutex_unlock(&pdev->sriov->lock);
 
79
                if (rc)
 
80
                        return rc;
 
81
        }
 
82
 
 
83
        if (!dev->is_physfn) {
 
84
                rc = ats_alloc_one(dev, ps);
 
85
                if (rc)
 
86
                        return rc;
 
87
        }
 
88
 
 
89
        ctrl = PCI_ATS_CTRL_ENABLE;
 
90
        if (!dev->is_virtfn)
 
91
                ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
 
92
        pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
 
93
 
 
94
        dev->ats->is_enabled = 1;
 
95
 
 
96
        return 0;
 
97
}
 
98
EXPORT_SYMBOL_GPL(pci_enable_ats);
 
99
 
 
100
/**
 
101
 * pci_disable_ats - disable the ATS capability
 
102
 * @dev: the PCI device
 
103
 */
 
104
void pci_disable_ats(struct pci_dev *dev)
 
105
{
 
106
        u16 ctrl;
 
107
 
 
108
        BUG_ON(!dev->ats || !dev->ats->is_enabled);
 
109
 
 
110
        pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
 
111
        ctrl &= ~PCI_ATS_CTRL_ENABLE;
 
112
        pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
 
113
 
 
114
        dev->ats->is_enabled = 0;
 
115
 
 
116
        if (dev->is_physfn || dev->is_virtfn) {
 
117
                struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
 
118
 
 
119
                mutex_lock(&pdev->sriov->lock);
 
120
                pdev->ats->ref_cnt--;
 
121
                if (!pdev->ats->ref_cnt)
 
122
                        ats_free_one(pdev);
 
123
                mutex_unlock(&pdev->sriov->lock);
 
124
        }
 
125
 
 
126
        if (!dev->is_physfn)
 
127
                ats_free_one(dev);
 
128
}
 
129
EXPORT_SYMBOL_GPL(pci_disable_ats);
 
130
 
 
131
/**
 
132
 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
 
133
 * @dev: the PCI device
 
134
 *
 
135
 * Returns the queue depth on success, or negative on failure.
 
136
 *
 
137
 * The ATS spec uses 0 in the Invalidate Queue Depth field to
 
138
 * indicate that the function can accept 32 Invalidate Request.
 
139
 * But here we use the `real' values (i.e. 1~32) for the Queue
 
140
 * Depth; and 0 indicates the function shares the Queue with
 
141
 * other functions (doesn't exclusively own a Queue).
 
142
 */
 
143
int pci_ats_queue_depth(struct pci_dev *dev)
 
144
{
 
145
        int pos;
 
146
        u16 cap;
 
147
 
 
148
        if (dev->is_virtfn)
 
149
                return 0;
 
150
 
 
151
        if (dev->ats)
 
152
                return dev->ats->qdep;
 
153
 
 
154
        pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
 
155
        if (!pos)
 
156
                return -ENODEV;
 
157
 
 
158
        pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
 
159
 
 
160
        return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
 
161
                                       PCI_ATS_MAX_QDEP;
 
162
}
 
163
EXPORT_SYMBOL_GPL(pci_ats_queue_depth);
 
164
 
 
165
#ifdef CONFIG_PCI_PRI
 
166
/**
 
167
 * pci_enable_pri - Enable PRI capability
 
168
 * @ pdev: PCI device structure
 
169
 *
 
170
 * Returns 0 on success, negative value on error
 
171
 */
 
172
int pci_enable_pri(struct pci_dev *pdev, u32 reqs)
 
173
{
 
174
        u16 control, status;
 
175
        u32 max_requests;
 
176
        int pos;
 
177
 
 
178
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
179
        if (!pos)
 
180
                return -EINVAL;
 
181
 
 
182
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
183
        pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF,  &status);
 
184
        if ((control & PCI_PRI_ENABLE) || !(status & PCI_PRI_STATUS_STOPPED))
 
185
                return -EBUSY;
 
186
 
 
187
        pci_read_config_dword(pdev, pos + PCI_PRI_MAX_REQ_OFF, &max_requests);
 
188
        reqs = min(max_requests, reqs);
 
189
        pci_write_config_dword(pdev, pos + PCI_PRI_ALLOC_REQ_OFF, reqs);
 
190
 
 
191
        control |= PCI_PRI_ENABLE;
 
192
        pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
 
193
 
 
194
        return 0;
 
195
}
 
196
EXPORT_SYMBOL_GPL(pci_enable_pri);
 
197
 
 
198
/**
 
199
 * pci_disable_pri - Disable PRI capability
 
200
 * @pdev: PCI device structure
 
201
 *
 
202
 * Only clears the enabled-bit, regardless of its former value
 
203
 */
 
204
void pci_disable_pri(struct pci_dev *pdev)
 
205
{
 
206
        u16 control;
 
207
        int pos;
 
208
 
 
209
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
210
        if (!pos)
 
211
                return;
 
212
 
 
213
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
214
        control &= ~PCI_PRI_ENABLE;
 
215
        pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
 
216
}
 
217
EXPORT_SYMBOL_GPL(pci_disable_pri);
 
218
 
 
219
/**
 
220
 * pci_pri_enabled - Checks if PRI capability is enabled
 
221
 * @pdev: PCI device structure
 
222
 *
 
223
 * Returns true if PRI is enabled on the device, false otherwise
 
224
 */
 
225
bool pci_pri_enabled(struct pci_dev *pdev)
 
226
{
 
227
        u16 control;
 
228
        int pos;
 
229
 
 
230
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
231
        if (!pos)
 
232
                return false;
 
233
 
 
234
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
235
 
 
236
        return (control & PCI_PRI_ENABLE) ? true : false;
 
237
}
 
238
EXPORT_SYMBOL_GPL(pci_pri_enabled);
 
239
 
 
240
/**
 
241
 * pci_reset_pri - Resets device's PRI state
 
242
 * @pdev: PCI device structure
 
243
 *
 
244
 * The PRI capability must be disabled before this function is called.
 
245
 * Returns 0 on success, negative value on error.
 
246
 */
 
247
int pci_reset_pri(struct pci_dev *pdev)
 
248
{
 
249
        u16 control;
 
250
        int pos;
 
251
 
 
252
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
253
        if (!pos)
 
254
                return -EINVAL;
 
255
 
 
256
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
257
        if (control & PCI_PRI_ENABLE)
 
258
                return -EBUSY;
 
259
 
 
260
        control |= PCI_PRI_RESET;
 
261
 
 
262
        pci_write_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, control);
 
263
 
 
264
        return 0;
 
265
}
 
266
EXPORT_SYMBOL_GPL(pci_reset_pri);
 
267
 
 
268
/**
 
269
 * pci_pri_stopped - Checks whether the PRI capability is stopped
 
270
 * @pdev: PCI device structure
 
271
 *
 
272
 * Returns true if the PRI capability on the device is disabled and the
 
273
 * device has no outstanding PRI requests, false otherwise. The device
 
274
 * indicates this via the STOPPED bit in the status register of the
 
275
 * capability.
 
276
 * The device internal state can be cleared by resetting the PRI state
 
277
 * with pci_reset_pri(). This can force the capability into the STOPPED
 
278
 * state.
 
279
 */
 
280
bool pci_pri_stopped(struct pci_dev *pdev)
 
281
{
 
282
        u16 control, status;
 
283
        int pos;
 
284
 
 
285
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
286
        if (!pos)
 
287
                return true;
 
288
 
 
289
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
290
        pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF,  &status);
 
291
 
 
292
        if (control & PCI_PRI_ENABLE)
 
293
                return false;
 
294
 
 
295
        return (status & PCI_PRI_STATUS_STOPPED) ? true : false;
 
296
}
 
297
EXPORT_SYMBOL_GPL(pci_pri_stopped);
 
298
 
 
299
/**
 
300
 * pci_pri_status - Request PRI status of a device
 
301
 * @pdev: PCI device structure
 
302
 *
 
303
 * Returns negative value on failure, status on success. The status can
 
304
 * be checked against status-bits. Supported bits are currently:
 
305
 * PCI_PRI_STATUS_RF:      Response failure
 
306
 * PCI_PRI_STATUS_UPRGI:   Unexpected Page Request Group Index
 
307
 * PCI_PRI_STATUS_STOPPED: PRI has stopped
 
308
 */
 
309
int pci_pri_status(struct pci_dev *pdev)
 
310
{
 
311
        u16 status, control;
 
312
        int pos;
 
313
 
 
314
        pos = pci_find_ext_capability(pdev, PCI_PRI_CAP);
 
315
        if (!pos)
 
316
                return -EINVAL;
 
317
 
 
318
        pci_read_config_word(pdev, pos + PCI_PRI_CONTROL_OFF, &control);
 
319
        pci_read_config_word(pdev, pos + PCI_PRI_STATUS_OFF,  &status);
 
320
 
 
321
        /* Stopped bit is undefined when enable == 1, so clear it */
 
322
        if (control & PCI_PRI_ENABLE)
 
323
                status &= ~PCI_PRI_STATUS_STOPPED;
 
324
 
 
325
        return status;
 
326
}
 
327
EXPORT_SYMBOL_GPL(pci_pri_status);
 
328
#endif /* CONFIG_PCI_PRI */
 
329
 
 
330
#ifdef CONFIG_PCI_PASID
 
331
/**
 
332
 * pci_enable_pasid - Enable the PASID capability
 
333
 * @pdev: PCI device structure
 
334
 * @features: Features to enable
 
335
 *
 
336
 * Returns 0 on success, negative value on error. This function checks
 
337
 * whether the features are actually supported by the device and returns
 
338
 * an error if not.
 
339
 */
 
340
int pci_enable_pasid(struct pci_dev *pdev, int features)
 
341
{
 
342
        u16 control, supported;
 
343
        int pos;
 
344
 
 
345
        pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
 
346
        if (!pos)
 
347
                return -EINVAL;
 
348
 
 
349
        pci_read_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, &control);
 
350
        pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF,     &supported);
 
351
 
 
352
        if (!(supported & PCI_PASID_ENABLE))
 
353
                return -EINVAL;
 
354
 
 
355
        supported &= PCI_PASID_EXEC | PCI_PASID_PRIV;
 
356
 
 
357
        /* User wants to enable anything unsupported? */
 
358
        if ((supported & features) != features)
 
359
                return -EINVAL;
 
360
 
 
361
        control = PCI_PASID_ENABLE | features;
 
362
 
 
363
        pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
 
364
 
 
365
        return 0;
 
366
}
 
367
EXPORT_SYMBOL_GPL(pci_enable_pasid);
 
368
 
 
369
/**
 
370
 * pci_disable_pasid - Disable the PASID capability
 
371
 * @pdev: PCI device structure
 
372
 *
 
373
 */
 
374
void pci_disable_pasid(struct pci_dev *pdev)
 
375
{
 
376
        u16 control = 0;
 
377
        int pos;
 
378
 
 
379
        pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
 
380
        if (!pos)
 
381
                return;
 
382
 
 
383
        pci_write_config_word(pdev, pos + PCI_PASID_CONTROL_OFF, control);
 
384
}
 
385
EXPORT_SYMBOL_GPL(pci_disable_pasid);
 
386
 
 
387
/**
 
388
 * pci_pasid_features - Check which PASID features are supported
 
389
 * @pdev: PCI device structure
 
390
 *
 
391
 * Returns a negative value when no PASI capability is present.
 
392
 * Otherwise is returns a bitmask with supported features. Current
 
393
 * features reported are:
 
394
 * PCI_PASID_ENABLE - PASID capability can be enabled
 
395
 * PCI_PASID_EXEC - Execute permission supported
 
396
 * PCI_PASID_PRIV - Priviledged mode supported
 
397
 */
 
398
int pci_pasid_features(struct pci_dev *pdev)
 
399
{
 
400
        u16 supported;
 
401
        int pos;
 
402
 
 
403
        pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
 
404
        if (!pos)
 
405
                return -EINVAL;
 
406
 
 
407
        pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
 
408
 
 
409
        supported &= PCI_PASID_ENABLE | PCI_PASID_EXEC | PCI_PASID_PRIV;
 
410
 
 
411
        return supported;
 
412
}
 
413
EXPORT_SYMBOL_GPL(pci_pasid_features);
 
414
 
 
415
#define PASID_NUMBER_SHIFT      8
 
416
#define PASID_NUMBER_MASK       (0x1f << PASID_NUMBER_SHIFT)
 
417
/**
 
418
 * pci_max_pasid - Get maximum number of PASIDs supported by device
 
419
 * @pdev: PCI device structure
 
420
 *
 
421
 * Returns negative value when PASID capability is not present.
 
422
 * Otherwise it returns the numer of supported PASIDs.
 
423
 */
 
424
int pci_max_pasids(struct pci_dev *pdev)
 
425
{
 
426
        u16 supported;
 
427
        int pos;
 
428
 
 
429
        pos = pci_find_ext_capability(pdev, PCI_PASID_CAP);
 
430
        if (!pos)
 
431
                return -EINVAL;
 
432
 
 
433
        pci_read_config_word(pdev, pos + PCI_PASID_CAP_OFF, &supported);
 
434
 
 
435
        supported = (supported & PASID_NUMBER_MASK) >> PASID_NUMBER_SHIFT;
 
436
 
 
437
        return (1 << supported);
 
438
}
 
439
EXPORT_SYMBOL_GPL(pci_max_pasids);
 
440
#endif /* CONFIG_PCI_PASID */