Subversion Repositories HelenOS

Rev

Rev 4399 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4399 trochtova 1
#include <malloc.h>
2
#include <assert.h>
3
#include <unistd.h>
4
#include <ddi.h>
5
#include <libarch/ddi.h>
6
#include <stdio.h>
7
#include <futex.h>
8
 
9
#include "pci.h"
10
#include "pci_bus.h"
11
 
12
#define PCI_CONF_OFFSET   0x001000000
13
#define PCI_CONF_SIZE     0x001000000
14
 
15
/*
16
 * virtual address of specified PCI configuration register:
17
 * conf_base ... base address of configuration address space
18
 * bus ... bus number
19
 * dev ... device number (0 - 31)
20
 * fn  ... function number (0 - 7)
21
 * reg ... register number (register's position within PCI configuration header)
22
 **/
23
#define CONF_ADDR(conf_base, bus, dev, fn, reg)   ((void *)(conf_base + ((bus << 16) | (dev << 11) | (fn << 8) | reg)))
24
 
25
static atomic_t pci_conf_futex = FUTEX_INITIALIZER;
26
 
27
static long u2p_space_cnt = 0;
28
static long *u2p_bases;
29
/* virtual addresses of PCI configuration spaces */
30
static void **conf_bases;  
31
 
32
static int psycho_init();
33
static void u2p_bases_init();
34
static void psycho_scan();
35
static void * psycho_conf_addr(pci_dev_t *dev, int reg);
36
static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len);
37
static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len);
38
 
39
 
40
static void * psycho_conf_addr(pci_dev_t *dev, int reg)
41
{  
42
    return CONF_ADDR(dev->bus->data, dev->bus->num, dev->dev, dev->fn, reg);
43
}
44
 
45
static void psycho_scan()
46
{  
47
    printf("PCI: psycho_scan\n");
48
    int i, num;
49
    for (i = 0; i < u2p_space_cnt; i++) {
50
        for (num = 0; num <= 0x80; num += 0x80) {      
51
            pci_bus_t *bus = pci_alloc_bus();
52
            bus->num = num;
53
            bus->data = conf_bases[i];
54
            pci_bus_register(bus);
55
            pci_bus_scan(bus);
56
        }
57
    }
58
}
59
 
60
static int psycho_init()
61
{
62
    printf("PCI: starting psycho initialization.\n");
63
    u2p_bases_init();
64
    conf_bases = (void **)malloc(u2p_space_cnt * sizeof(void *));  
65
    int i, error;
66
    for (i = 0; i < u2p_space_cnt; i++) {
67
        if (error = pio_enable((void *)(u2p_bases[i] + PCI_CONF_OFFSET), PCI_CONF_SIZE, &(conf_bases[i]))) {
68
            printf("PCI: failed to enable psycho conf. adr. space num. %d. (error %d)\n", i, error);
69
            return 0;
70
        }
71
    }  
72
    return 1;
73
}
74
 
75
static void u2p_bases_init()
76
{
77
    // TODO: write this more generally - get this information from firmware (using kernel + sysinfo)    
78
    u2p_space_cnt = 2;
79
    //u2p_space_cnt = 1;
80
    u2p_bases = (void **)malloc(u2p_space_cnt * sizeof(void *));
81
    u2p_bases[0] = 0x1c800000000;
82
    u2p_bases[1] = 0x1ca00000000;  
83
}
84
 
85
uint8_t pci_conf_read_8(pci_dev_t *dev, int reg)
86
{
87
    uint8_t res;
88
    futex_down(&pci_conf_futex);
89
    psycho_conf_read(dev, reg, &res, sizeof(uint8_t)); 
90
    futex_up(&pci_conf_futex);
91
    return res;
92
}
93
 
94
uint16_t pci_conf_read_16(pci_dev_t *dev, int reg)
95
{
96
    uint16_t res;
97
    futex_down(&pci_conf_futex);
98
    psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint16_t));   
99
    futex_up(&pci_conf_futex);
100
    return res;
101
}
102
 
103
uint32_t pci_conf_read_32(pci_dev_t *dev, int reg)
104
{
105
    uint32_t res;
106
    futex_down(&pci_conf_futex);
107
    psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint32_t));   
108
    futex_up(&pci_conf_futex);
109
    return res;
110
}
111
 
4418 trochtova 112
static inline uint16_t invert_endianness_16(uint16_t x)
4399 trochtova 113
{
114
    return (x & 0xFF) << 8 | (x >> 8);
115
}
116
 
4418 trochtova 117
static inline uint32_t invert_endianness_32(uint32_t x)
4399 trochtova 118
{
119
    return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);
120
}
121
 
122
static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len)
123
{  
124
    switch (len) {
125
        case 1:
126
            buf[0] = pio_read_8(psycho_conf_addr(d, reg));
127
            break;
128
        case 2:
4418 trochtova 129
            *((uint16_t *)buf) = invert_endianness_16(pio_read_16(psycho_conf_addr(d, reg)));
4399 trochtova 130
            break;
131
        case 4:
4418 trochtova 132
            *((uint32_t *)buf) = invert_endianness_32(pio_read_32(psycho_conf_addr(d, reg)));
4399 trochtova 133
            break;
134
    }  
135
}
136
 
137
static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len)
138
{  
139
    switch (len) {
140
        case 1:
141
            pio_write_8(psycho_conf_addr(d, reg), buf[0]);
142
            break;
143
        case 2:
4418 trochtova 144
            pio_write_16(psycho_conf_addr(d, reg), invert_endianness_16(*((uint16_t *)buf)));
4399 trochtova 145
            break;
146
        case 4:
4418 trochtova 147
            pio_write_32(psycho_conf_addr(d, reg), invert_endianness_32(*((uint32_t *)buf)));
4399 trochtova 148
            break;
149
    }
150
}
151
 
152
/* pci bus structure initialization */
153
void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent)
154
{
155
    if (parent != NULL) {
156
        bus->data = parent->data;
157
    }
158
}
159
 
160
int pci_bus_init()
161
{  
162
    if(!psycho_init()) {
163
        return 0;
164
    }  
165
    psycho_scan(); 
166
    return 1;
167
}
168
 
169
void pci_bus_clean()
170
{
171
    free(u2p_bases);
172
    free(conf_bases);
173
}