Root/target/linux/lantiq/files/arch/mips/pci/pcie-lantiq-msi.c

1/******************************************************************************
2**
3** FILE NAME : ifxmips_pcie_msi.c
4** PROJECT : IFX UEIP for VRX200
5** MODULES : PCI MSI sub module
6**
7** DATE : 02 Mar 2009
8** AUTHOR : Lei Chuanhua
9** DESCRIPTION : PCIe MSI Driver
10** COPYRIGHT : Copyright (c) 2009
11** Infineon Technologies AG
12** Am Campeon 1-12, 85579 Neubiberg, Germany
13**
14** This program is free software; you can redistribute it and/or modify
15** it under the terms of the GNU General Public License as published by
16** the Free Software Foundation; either version 2 of the License, or
17** (at your option) any later version.
18** HISTORY
19** $Date $Author $Comment
20** 02 Mar,2009 Lei Chuanhua Initial version
21*******************************************************************************/
22/*!
23 \defgroup IFX_PCIE_MSI MSI OS APIs
24 \ingroup IFX_PCIE
25 \brief PCIe bus driver OS interface functions
26*/
27
28/*!
29 \file ifxmips_pcie_msi.c
30 \ingroup IFX_PCIE
31 \brief PCIe MSI OS interface file
32*/
33
34#include <linux/init.h>
35#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/interrupt.h>
38#include <linux/kernel_stat.h>
39#include <linux/pci.h>
40#include <linux/msi.h>
41#include <linux/module.h>
42#include <asm/bootinfo.h>
43#include <asm/irq.h>
44#include <asm/traps.h>
45
46#include "pcie-lantiq.h"
47
48#define IFX_MSI_IRQ_NUM 16
49#define SM(_v, _f) (((_v) << _f##_S) & (_f))
50
51#define IFX_MSI_PIC_REG_BASE (KSEG1 | 0x1F700000)
52#define IFX_PCIE_MSI_IR0 (INT_NUM_IM4_IRL0 + 27)
53#define IFX_PCIE_MSI_IR1 (INT_NUM_IM4_IRL0 + 28)
54#define IFX_PCIE_MSI_IR2 (INT_NUM_IM4_IRL0 + 29)
55#define IFX_PCIE_MSI_IR3 (INT_NUM_IM0_IRL0 + 30)
56
57#define IFX_MSI_PCI_INT_DISABLE 0x80000000
58#define IFX_MSI_PIC_INT_LINE 0x30000000
59#define IFX_MSI_PIC_MSG_ADDR 0x0FFF0000
60#define IFX_MSI_PIC_MSG_DATA 0x0000FFFF
61#define IFX_MSI_PIC_BIG_ENDIAN 1
62#define IFX_MSI_PIC_INT_LINE_S 28
63#define IFX_MSI_PIC_MSG_ADDR_S 16
64#define IFX_MSI_PIC_MSG_DATA_S 0x0
65
66enum {
67    IFX_PCIE_MSI_IDX0 = 0,
68    IFX_PCIE_MSI_IDX1,
69    IFX_PCIE_MSI_IDX2,
70    IFX_PCIE_MSI_IDX3,
71};
72
73typedef struct ifx_msi_irq_idx {
74    const int irq;
75    const int idx;
76}ifx_msi_irq_idx_t;
77
78struct ifx_msi_pic {
79    volatile u32 pic_table[IFX_MSI_IRQ_NUM];
80    volatile u32 pic_endian; /* 0x40 */
81};
82typedef struct ifx_msi_pic *ifx_msi_pic_t;
83
84typedef struct ifx_msi_irq {
85    const volatile ifx_msi_pic_t msi_pic_p;
86    const u32 msi_phy_base;
87    const ifx_msi_irq_idx_t msi_irq_idx[IFX_MSI_IRQ_NUM];
88    /*
89     * Each bit in msi_free_irq_bitmask represents a MSI interrupt that is
90     * in use.
91     */
92    u16 msi_free_irq_bitmask;
93
94    /*
95     * Each bit in msi_multiple_irq_bitmask tells that the device using
96     * this bit in msi_free_irq_bitmask is also using the next bit. This
97     * is used so we can disable all of the MSI interrupts when a device
98     * uses multiple.
99     */
100    u16 msi_multiple_irq_bitmask;
101}ifx_msi_irq_t;
102
103static ifx_msi_irq_t msi_irqs[IFX_PCIE_CORE_NR] = {
104    {
105        .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI_PIC_REG_BASE,
106        .msi_phy_base = PCIE_MSI_PHY_BASE,
107        .msi_irq_idx = {
108            {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
109            {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
110            {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
111            {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
112            {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
113            {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
114            {IFX_PCIE_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE_MSI_IR1, IFX_PCIE_MSI_IDX1},
115            {IFX_PCIE_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE_MSI_IR3, IFX_PCIE_MSI_IDX3},
116        },
117        .msi_free_irq_bitmask = 0,
118        .msi_multiple_irq_bitmask= 0,
119    },
120#ifdef CONFIG_IFX_PCIE_2ND_CORE
121    {
122        .msi_pic_p = (const volatile ifx_msi_pic_t)IFX_MSI1_PIC_REG_BASE,
123        .msi_phy_base = PCIE1_MSI_PHY_BASE,
124        .msi_irq_idx = {
125            {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
126            {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
127            {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
128            {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
129            {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
130            {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
131            {IFX_PCIE1_MSI_IR0, IFX_PCIE_MSI_IDX0}, {IFX_PCIE1_MSI_IR1, IFX_PCIE_MSI_IDX1},
132            {IFX_PCIE1_MSI_IR2, IFX_PCIE_MSI_IDX2}, {IFX_PCIE1_MSI_IR3, IFX_PCIE_MSI_IDX3},
133        },
134        .msi_free_irq_bitmask = 0,
135        .msi_multiple_irq_bitmask= 0,
136
137    },
138#endif /* CONFIG_IFX_PCIE_2ND_CORE */
139};
140
141/*
142 * This lock controls updates to msi_free_irq_bitmask,
143 * msi_multiple_irq_bitmask and pic register settting
144 */
145static DEFINE_SPINLOCK(ifx_pcie_msi_lock);
146
147void pcie_msi_pic_init(int pcie_port)
148{
149    spin_lock(&ifx_pcie_msi_lock);
150    msi_irqs[pcie_port].msi_pic_p->pic_endian = IFX_MSI_PIC_BIG_ENDIAN;
151    spin_unlock(&ifx_pcie_msi_lock);
152}
153
154/**
155 * \fn int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
156 * \brief Called when a driver request MSI interrupts instead of the
157 * legacy INT A-D. This routine will allocate multiple interrupts
158 * for MSI devices that support them. A device can override this by
159 * programming the MSI control bits [6:4] before calling
160 * pci_enable_msi().
161 *
162 * \param[in] pdev Device requesting MSI interrupts
163 * \param[in] desc MSI descriptor
164 *
165 * \return -EINVAL Invalid pcie root port or invalid msi bit
166 * \return 0 OK
167 * \ingroup IFX_PCIE_MSI
168 */
169int
170arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
171{
172    int irq, pos;
173    u16 control;
174    int irq_idx;
175    int irq_step;
176    int configured_private_bits;
177    int request_private_bits;
178    struct msi_msg msg;
179    u16 search_mask;
180    struct ifx_pci_controller *ctrl = pdev->bus->sysdata;
181    int pcie_port = ctrl->port;
182
183    IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s %s enter\n", __func__, pci_name(pdev));
184
185    /* XXX, skip RC MSI itself */
186    if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT) {
187        IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s RC itself doesn't use MSI interrupt\n", __func__);
188        return -EINVAL;
189    }
190
191    /*
192     * Read the MSI config to figure out how many IRQs this device
193     * wants. Most devices only want 1, which will give
194     * configured_private_bits and request_private_bits equal 0.
195     */
196    pci_read_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &control);
197
198    /*
199     * If the number of private bits has been configured then use
200     * that value instead of the requested number. This gives the
201     * driver the chance to override the number of interrupts
202     * before calling pci_enable_msi().
203     */
204    configured_private_bits = (control & PCI_MSI_FLAGS_QSIZE) >> 4;
205    if (configured_private_bits == 0) {
206        /* Nothing is configured, so use the hardware requested size */
207        request_private_bits = (control & PCI_MSI_FLAGS_QMASK) >> 1;
208    }
209    else {
210        /*
211         * Use the number of configured bits, assuming the
212         * driver wanted to override the hardware request
213         * value.
214         */
215        request_private_bits = configured_private_bits;
216    }
217
218    /*
219     * The PCI 2.3 spec mandates that there are at most 32
220     * interrupts. If this device asks for more, only give it one.
221     */
222    if (request_private_bits > 5) {
223        request_private_bits = 0;
224    }
225again:
226    /*
227     * The IRQs have to be aligned on a power of two based on the
228     * number being requested.
229     */
230    irq_step = (1 << request_private_bits);
231
232    /* Mask with one bit for each IRQ */
233    search_mask = (1 << irq_step) - 1;
234
235    /*
236     * We're going to search msi_free_irq_bitmask_lock for zero
237     * bits. This represents an MSI interrupt number that isn't in
238     * use.
239     */
240    spin_lock(&ifx_pcie_msi_lock);
241    for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos += irq_step) {
242        if ((msi_irqs[pcie_port].msi_free_irq_bitmask & (search_mask << pos)) == 0) {
243            msi_irqs[pcie_port].msi_free_irq_bitmask |= search_mask << pos;
244            msi_irqs[pcie_port].msi_multiple_irq_bitmask |= (search_mask >> 1) << pos;
245            break;
246        }
247    }
248    spin_unlock(&ifx_pcie_msi_lock);
249
250    /* Make sure the search for available interrupts didn't fail */
251    if (pos >= IFX_MSI_IRQ_NUM) {
252        if (request_private_bits) {
253            IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s: Unable to find %d free "
254                  "interrupts, trying just one", __func__, 1 << request_private_bits);
255            request_private_bits = 0;
256            goto again;
257        }
258        else {
259            printk(KERN_ERR "%s: Unable to find a free MSI interrupt\n", __func__);
260            return -EINVAL;
261        }
262    }
263    irq = msi_irqs[pcie_port].msi_irq_idx[pos].irq;
264    irq_idx = msi_irqs[pcie_port].msi_irq_idx[pos].idx;
265
266    IFX_PCIE_PRINT(PCIE_MSG_MSI, "pos %d, irq %d irq_idx %d\n", pos, irq, irq_idx);
267
268    /*
269     * Initialize MSI. This has to match the memory-write endianess from the device
270     * Address bits [23:12]
271     */
272    spin_lock(&ifx_pcie_msi_lock);
273    msi_irqs[pcie_port].msi_pic_p->pic_table[pos] = SM(irq_idx, IFX_MSI_PIC_INT_LINE) |
274                    SM((msi_irqs[pcie_port].msi_phy_base >> 12), IFX_MSI_PIC_MSG_ADDR) |
275                    SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
276
277    /* Enable this entry */
278    msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~IFX_MSI_PCI_INT_DISABLE;
279    spin_unlock(&ifx_pcie_msi_lock);
280
281    IFX_PCIE_PRINT(PCIE_MSG_MSI, "pic_table[%d]: 0x%08x\n",
282        pos, msi_irqs[pcie_port].msi_pic_p->pic_table[pos]);
283
284    /* Update the number of IRQs the device has available to it */
285    control &= ~PCI_MSI_FLAGS_QSIZE;
286    control |= (request_private_bits << 4);
287    pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS, control);
288
289    irq_set_msi_desc(irq, desc);
290    msg.address_hi = 0x0;
291    msg.address_lo = msi_irqs[pcie_port].msi_phy_base;
292    msg.data = SM((1 << pos), IFX_MSI_PIC_MSG_DATA);
293    IFX_PCIE_PRINT(PCIE_MSG_MSI, "msi_data: pos %d 0x%08x\n", pos, msg.data);
294
295    write_msi_msg(irq, &msg);
296    IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
297    return 0;
298}
299
300static int
301pcie_msi_irq_to_port(unsigned int irq, int *port)
302{
303    int ret = 0;
304
305    if (irq == IFX_PCIE_MSI_IR0 || irq == IFX_PCIE_MSI_IR1 ||
306        irq == IFX_PCIE_MSI_IR2 || irq == IFX_PCIE_MSI_IR3) {
307        *port = IFX_PCIE_PORT0;
308    }
309#ifdef CONFIG_IFX_PCIE_2ND_CORE
310    else if (irq == IFX_PCIE1_MSI_IR0 || irq == IFX_PCIE1_MSI_IR1 ||
311        irq == IFX_PCIE1_MSI_IR2 || irq == IFX_PCIE1_MSI_IR3) {
312        *port = IFX_PCIE_PORT1;
313    }
314#endif /* CONFIG_IFX_PCIE_2ND_CORE */
315    else {
316        printk(KERN_ERR "%s: Attempted to teardown illegal "
317            "MSI interrupt (%d)\n", __func__, irq);
318        ret = -EINVAL;
319    }
320    return ret;
321}
322
323/**
324 * \fn void arch_teardown_msi_irq(unsigned int irq)
325 * \brief Called when a device no longer needs its MSI interrupts. All
326 * MSI interrupts for the device are freed.
327 *
328 * \param irq The devices first irq number. There may be multple in sequence.
329 * \return none
330 * \ingroup IFX_PCIE_MSI
331 */
332void
333arch_teardown_msi_irq(unsigned int irq)
334{
335    int pos;
336    int number_irqs;
337    u16 bitmask;
338    int pcie_port;
339
340    IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s enter\n", __func__);
341
342    BUG_ON(irq > (INT_NUM_IM4_IRL0 + 31));
343
344    if (pcie_msi_irq_to_port(irq, &pcie_port) != 0) {
345        return;
346    }
347
348    /* Shift the mask to the correct bit location, not always correct
349     * Probally, the first match will be chosen.
350     */
351    for (pos = 0; pos < IFX_MSI_IRQ_NUM; pos++) {
352        if ((msi_irqs[pcie_port].msi_irq_idx[pos].irq == irq)
353            && (msi_irqs[pcie_port].msi_free_irq_bitmask & ( 1 << pos))) {
354            break;
355        }
356    }
357    if (pos >= IFX_MSI_IRQ_NUM) {
358        printk(KERN_ERR "%s: Unable to find a matched MSI interrupt\n", __func__);
359        return;
360    }
361    spin_lock(&ifx_pcie_msi_lock);
362    /* Disable this entry */
363    msi_irqs[pcie_port].msi_pic_p->pic_table[pos] |= IFX_MSI_PCI_INT_DISABLE;
364    msi_irqs[pcie_port].msi_pic_p->pic_table[pos] &= ~(IFX_MSI_PIC_INT_LINE | IFX_MSI_PIC_MSG_ADDR | IFX_MSI_PIC_MSG_DATA);
365    spin_unlock(&ifx_pcie_msi_lock);
366    /*
367     * Count the number of IRQs we need to free by looking at the
368     * msi_multiple_irq_bitmask. Each bit set means that the next
369     * IRQ is also owned by this device.
370     */
371    number_irqs = 0;
372    while (((pos + number_irqs) < IFX_MSI_IRQ_NUM) &&
373        (msi_irqs[pcie_port].msi_multiple_irq_bitmask & (1 << (pos + number_irqs)))) {
374        number_irqs++;
375    }
376    number_irqs++;
377
378    /* Mask with one bit for each IRQ */
379    bitmask = (1 << number_irqs) - 1;
380
381    bitmask <<= pos;
382    if ((msi_irqs[pcie_port].msi_free_irq_bitmask & bitmask) != bitmask) {
383        printk(KERN_ERR "%s: Attempted to teardown MSI "
384             "interrupt (%d) not in use\n", __func__, irq);
385        return;
386    }
387    /* Checks are done, update the in use bitmask */
388    spin_lock(&ifx_pcie_msi_lock);
389    msi_irqs[pcie_port].msi_free_irq_bitmask &= ~bitmask;
390    msi_irqs[pcie_port].msi_multiple_irq_bitmask &= ~(bitmask >> 1);
391    spin_unlock(&ifx_pcie_msi_lock);
392    IFX_PCIE_PRINT(PCIE_MSG_MSI, "%s exit\n", __func__);
393}
394
395MODULE_LICENSE("GPL");
396MODULE_AUTHOR("Chuanhua.Lei@infineon.com");
397MODULE_SUPPORTED_DEVICE("Infineon PCIe IP builtin MSI PIC module");
398MODULE_DESCRIPTION("Infineon PCIe IP builtin MSI PIC driver");
399
400

Archive Download this file



interactive