Subversion Repositories HelenOS

Rev

Rev 4418 | 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
{
4438 trochtova 87
    uint8_t res;   
4399 trochtova 88
    psycho_conf_read(dev, reg, &res, sizeof(uint8_t)); 
89
    return res;
90
}
91
 
92
uint16_t pci_conf_read_16(pci_dev_t *dev, int reg)
93
{
94
    uint16_t res;
95
    psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint16_t));   
96
    return res;
97
}
98
 
99
uint32_t pci_conf_read_32(pci_dev_t *dev, int reg)
100
{
101
    uint32_t res;
4438 trochtova 102
    psycho_conf_read(dev, reg, (uint8_t *)(&res), sizeof(uint32_t));       
4399 trochtova 103
    return res;
104
}
105
 
4418 trochtova 106
static inline uint16_t invert_endianness_16(uint16_t x)
4399 trochtova 107
{
108
    return (x & 0xFF) << 8 | (x >> 8);
109
}
110
 
4418 trochtova 111
static inline uint32_t invert_endianness_32(uint32_t x)
4399 trochtova 112
{
113
    return ((x & 0xFF) << 24) | ((x & 0xFF00) << 8) | ((x & 0xFF0000) >> 8) | (x >> 24);
114
}
115
 
116
static void psycho_conf_read(pci_dev_t *d, int reg, uint8_t *buf, int len)
117
{  
4438 trochtova 118
    futex_down(&pci_conf_futex);
4399 trochtova 119
    switch (len) {
120
        case 1:
121
            buf[0] = pio_read_8(psycho_conf_addr(d, reg));
122
            break;
123
        case 2:
4418 trochtova 124
            *((uint16_t *)buf) = invert_endianness_16(pio_read_16(psycho_conf_addr(d, reg)));
4399 trochtova 125
            break;
126
        case 4:
4418 trochtova 127
            *((uint32_t *)buf) = invert_endianness_32(pio_read_32(psycho_conf_addr(d, reg)));
4399 trochtova 128
            break;
4438 trochtova 129
    }
130
    futex_up(&pci_conf_futex);
4399 trochtova 131
}
132
 
133
static void psycho_conf_write(pci_dev_t *d, int reg, uint8_t *buf, int len)
134
{  
4438 trochtova 135
    futex_down(&pci_conf_futex);
4399 trochtova 136
    switch (len) {
137
        case 1:
138
            pio_write_8(psycho_conf_addr(d, reg), buf[0]);
139
            break;
140
        case 2:
4418 trochtova 141
            pio_write_16(psycho_conf_addr(d, reg), invert_endianness_16(*((uint16_t *)buf)));
4399 trochtova 142
            break;
143
        case 4:
4418 trochtova 144
            pio_write_32(psycho_conf_addr(d, reg), invert_endianness_32(*((uint32_t *)buf)));
4399 trochtova 145
            break;
146
    }
4438 trochtova 147
    futex_up(&pci_conf_futex);
4399 trochtova 148
}
149
 
150
/* pci bus structure initialization */
151
void pci_init_bus_data(pci_bus_t *bus, pci_bus_t *parent)
152
{
153
    if (parent != NULL) {
154
        bus->data = parent->data;
155
    }
156
}
157
 
158
int pci_bus_init()
159
{  
160
    if(!psycho_init()) {
161
        return 0;
162
    }  
163
    psycho_scan(); 
164
    return 1;
165
}
166
 
167
void pci_bus_clean()
168
{
169
    free(u2p_bases);
170
    free(conf_bases);
171
}