Commit d2b5931756fdb9f839180e33898cd1e3e4fbdc90

Authored by pbrook
1 parent e69954b9

PCI shared IRQ fix (original patch by andrzej zaborowski).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2165 c046a42c-6fe2-441c-8c8c-71466251a162
hw/apb_pci.c
@@ -179,10 +179,18 @@ static CPUReadMemoryFunc *pci_apb_ioread[] = { @@ -179,10 +179,18 @@ static CPUReadMemoryFunc *pci_apb_ioread[] = {
179 &pci_apb_ioreadl, 179 &pci_apb_ioreadl,
180 }; 180 };
181 181
182 -/* ??? This is probably wrong. */  
183 -static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) 182 +static int pci_apb_map_irq(PCIDevice *pci_dev, int irq_num)
184 { 183 {
185 - pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level); 184 + /* ??? As mentioned below this is probably wrong. */
  185 + return irq_num;
  186 +}
  187 +
  188 +static void pci_apb_set_irq(void *pic, int irq_num, int level)
  189 +{
  190 + /* ??? This is almost certainly wrong. However the rest of the sun4u
  191 + IRQ handling is missing, as is OpenBIOS support, so it wouldn't work
  192 + anyway. */
  193 + pic_set_irq_new(pic, irq_num, level);
186 } 194 }
187 195
188 PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, 196 PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
@@ -194,7 +202,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base, @@ -194,7 +202,7 @@ PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
194 202
195 s = qemu_mallocz(sizeof(APBState)); 203 s = qemu_mallocz(sizeof(APBState));
196 /* Ultrasparc APB main bus */ 204 /* Ultrasparc APB main bus */
197 - s->bus = pci_register_bus(pci_apb_set_irq, pic, 0); 205 + s->bus = pci_register_bus(pci_apb_set_irq, pci_apb_map_irq, pic, 0);
198 206
199 pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read, 207 pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
200 pci_apb_config_write, s); 208 pci_apb_config_write, s);
hw/grackle_pci.c
@@ -74,11 +74,15 @@ static CPUReadMemoryFunc *pci_grackle_read[] = { @@ -74,11 +74,15 @@ static CPUReadMemoryFunc *pci_grackle_read[] = {
74 &pci_host_data_readl, 74 &pci_host_data_readl,
75 }; 75 };
76 76
77 -/* XXX: we do not simulate the hardware - we rely on the BIOS to  
78 - set correctly for irq line field */  
79 -static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level) 77 +/* Don't know if this matches real hardware, but it agrees with OHW. */
  78 +static int pci_grackle_map_irq(PCIDevice *pci_dev, int irq_num)
80 { 79 {
81 - heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); 80 + return (irq_num + (pci_dev->devfn >> 3)) & 3;
  81 +}
  82 +
  83 +static void pci_grackle_set_irq(void *pic, int irq_num, int level)
  84 +{
  85 + heathrow_pic_set_irq(pic, irq_num + 8, level);
82 } 86 }
83 87
84 PCIBus *pci_grackle_init(uint32_t base, void *pic) 88 PCIBus *pci_grackle_init(uint32_t base, void *pic)
@@ -88,7 +92,7 @@ PCIBus *pci_grackle_init(uint32_t base, void *pic) @@ -88,7 +92,7 @@ PCIBus *pci_grackle_init(uint32_t base, void *pic)
88 int pci_mem_config, pci_mem_data; 92 int pci_mem_config, pci_mem_data;
89 93
90 s = qemu_mallocz(sizeof(GrackleState)); 94 s = qemu_mallocz(sizeof(GrackleState));
91 - s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0); 95 + s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq, pic, 0);
92 96
93 pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, 97 pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
94 pci_grackle_config_write, s); 98 pci_grackle_config_write, s);
hw/pci.c
@@ -29,11 +29,15 @@ struct PCIBus { @@ -29,11 +29,15 @@ struct PCIBus {
29 int bus_num; 29 int bus_num;
30 int devfn_min; 30 int devfn_min;
31 pci_set_irq_fn set_irq; 31 pci_set_irq_fn set_irq;
  32 + pci_map_irq_fn map_irq;
32 uint32_t config_reg; /* XXX: suppress */ 33 uint32_t config_reg; /* XXX: suppress */
33 /* low level pic */ 34 /* low level pic */
34 SetIRQFunc *low_set_irq; 35 SetIRQFunc *low_set_irq;
35 void *irq_opaque; 36 void *irq_opaque;
36 PCIDevice *devices[256]; 37 PCIDevice *devices[256];
  38 + /* The bus IRQ state is the logical OR of the connected devices.
  39 + Keep a count of the number of devices with raised IRQs. */
  40 + int irq_count[4];
37 }; 41 };
38 42
39 static void pci_update_mappings(PCIDevice *d); 43 static void pci_update_mappings(PCIDevice *d);
@@ -42,13 +46,16 @@ target_phys_addr_t pci_mem_base; @@ -42,13 +46,16 @@ target_phys_addr_t pci_mem_base;
42 static int pci_irq_index; 46 static int pci_irq_index;
43 static PCIBus *first_bus; 47 static PCIBus *first_bus;
44 48
45 -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min) 49 +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
  50 + void *pic, int devfn_min)
46 { 51 {
47 PCIBus *bus; 52 PCIBus *bus;
48 bus = qemu_mallocz(sizeof(PCIBus)); 53 bus = qemu_mallocz(sizeof(PCIBus));
49 bus->set_irq = set_irq; 54 bus->set_irq = set_irq;
  55 + bus->map_irq = map_irq;
50 bus->irq_opaque = pic; 56 bus->irq_opaque = pic;
51 bus->devfn_min = devfn_min; 57 bus->devfn_min = devfn_min;
  58 + memset(bus->irq_count, 0, sizeof(bus->irq_count));
52 first_bus = bus; 59 first_bus = bus;
53 return bus; 60 return bus;
54 } 61 }
@@ -100,6 +107,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name, @@ -100,6 +107,7 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
100 pci_dev->bus = bus; 107 pci_dev->bus = bus;
101 pci_dev->devfn = devfn; 108 pci_dev->devfn = devfn;
102 pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); 109 pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
  110 + memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
103 111
104 if (!config_read) 112 if (!config_read)
105 config_read = pci_default_read_config; 113 config_read = pci_default_read_config;
@@ -404,7 +412,11 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len) @@ -404,7 +412,11 @@ uint32_t pci_data_read(void *opaque, uint32_t addr, int len)
404 void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level) 412 void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
405 { 413 {
406 PCIBus *bus = pci_dev->bus; 414 PCIBus *bus = pci_dev->bus;
407 - bus->set_irq(pci_dev, bus->irq_opaque, irq_num, level); 415 +
  416 + irq_num = bus->map_irq(pci_dev, irq_num);
  417 + bus->irq_count[irq_num] += level - pci_dev->irq_state[irq_num];
  418 + pci_dev->irq_state[irq_num] = level;
  419 + bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
408 } 420 }
409 421
410 /***********************************************************/ 422 /***********************************************************/
hw/piix_pci.c
@@ -40,7 +40,17 @@ static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) @@ -40,7 +40,17 @@ static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
40 return s->config_reg; 40 return s->config_reg;
41 } 41 }
42 42
43 -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level); 43 +static void piix3_set_irq(void *pic, int irq_num, int level);
  44 +
  45 +/* return the global irq number corresponding to a given device irq
  46 + pin. We could also use the bus number to have a more precise
  47 + mapping. */
  48 +static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
  49 +{
  50 + int slot_addend;
  51 + slot_addend = (pci_dev->devfn >> 3) - 1;
  52 + return (irq_num + slot_addend) & 3;
  53 +}
44 54
45 PCIBus *i440fx_init(void) 55 PCIBus *i440fx_init(void)
46 { 56 {
@@ -49,7 +59,7 @@ PCIBus *i440fx_init(void) @@ -49,7 +59,7 @@ PCIBus *i440fx_init(void)
49 I440FXState *s; 59 I440FXState *s;
50 60
51 s = qemu_mallocz(sizeof(I440FXState)); 61 s = qemu_mallocz(sizeof(I440FXState));
52 - b = pci_register_bus(piix3_set_irq, NULL, 0); 62 + b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0);
53 s->bus = b; 63 s->bus = b;
54 64
55 register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); 65 register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
@@ -83,65 +93,25 @@ static PCIDevice *piix3_dev; @@ -83,65 +93,25 @@ static PCIDevice *piix3_dev;
83 /* just used for simpler irq handling. */ 93 /* just used for simpler irq handling. */
84 #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32) 94 #define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
85 95
86 -static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];  
87 -  
88 -/* return the global irq number corresponding to a given device irq  
89 - pin. We could also use the bus number to have a more precise  
90 - mapping. */  
91 -static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)  
92 -{  
93 - int slot_addend;  
94 - slot_addend = (pci_dev->devfn >> 3) - 1;  
95 - return (irq_num + slot_addend) & 3;  
96 -}  
97 -  
98 -static inline int get_pci_irq_level(int irq_num)  
99 -{  
100 - int pic_level;  
101 -#if (PCI_IRQ_WORDS == 2)  
102 - pic_level = ((pci_irq_levels[irq_num][0] |  
103 - pci_irq_levels[irq_num][1]) != 0);  
104 -#else  
105 - {  
106 - int i;  
107 - pic_level = 0;  
108 - for(i = 0; i < PCI_IRQ_WORDS; i++) {  
109 - if (pci_irq_levels[irq_num][i]) {  
110 - pic_level = 1;  
111 - break;  
112 - }  
113 - }  
114 - }  
115 -#endif  
116 - return pic_level;  
117 -} 96 +static int pci_irq_levels[4];
118 97
119 -static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level) 98 +static void piix3_set_irq(void *pic, int irq_num, int level)
120 { 99 {
121 - int irq_index, shift, pic_irq, pic_level;  
122 - uint32_t *p; 100 + int i, pic_irq, pic_level;
123 101
124 - irq_num = pci_slot_get_pirq(pci_dev, irq_num);  
125 - irq_index = pci_dev->irq_index;  
126 - p = &pci_irq_levels[irq_num][irq_index >> 5];  
127 - shift = (irq_index & 0x1f);  
128 - *p = (*p & ~(1 << shift)) | (level << shift); 102 + pci_irq_levels[irq_num] = level;
129 103
130 /* now we change the pic irq level according to the piix irq mappings */ 104 /* now we change the pic irq level according to the piix irq mappings */
131 /* XXX: optimize */ 105 /* XXX: optimize */
132 pic_irq = piix3_dev->config[0x60 + irq_num]; 106 pic_irq = piix3_dev->config[0x60 + irq_num];
133 if (pic_irq < 16) { 107 if (pic_irq < 16) {
134 - /* the pic level is the logical OR of all the PCI irqs mapped 108 + /* The pic level is the logical OR of all the PCI irqs mapped
135 to it */ 109 to it */
136 pic_level = 0; 110 pic_level = 0;
137 - if (pic_irq == piix3_dev->config[0x60])  
138 - pic_level |= get_pci_irq_level(0);  
139 - if (pic_irq == piix3_dev->config[0x61])  
140 - pic_level |= get_pci_irq_level(1);  
141 - if (pic_irq == piix3_dev->config[0x62])  
142 - pic_level |= get_pci_irq_level(2);  
143 - if (pic_irq == piix3_dev->config[0x63])  
144 - pic_level |= get_pci_irq_level(3); 111 + for (i = 0; i < 4; i++) {
  112 + if (pic_irq == piix3_dev->config[0x60 + i])
  113 + pic_level |= pci_irq_levels[i];
  114 + }
145 pic_set_irq(pic_irq, pic_level); 115 pic_set_irq(pic_irq, pic_level);
146 } 116 }
147 } 117 }
hw/prep_pci.c
@@ -117,11 +117,21 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = { @@ -117,11 +117,21 @@ static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
117 &PPC_PCIIO_readl, 117 &PPC_PCIIO_readl,
118 }; 118 };
119 119
120 -static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level) 120 +/* Don't know if this matches real hardware, but it agrees with OHW. */
  121 +static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
121 { 122 {
122 - /* XXX: we do not simulate the hardware - we rely on the BIOS to  
123 - set correctly for irq line field */  
124 - pic_set_irq(d->config[PCI_INTERRUPT_LINE], level); 123 + return (irq_num + (pci_dev->devfn >> 3)) & 3;
  124 +}
  125 +
  126 +static int prep_irq_levels[4];
  127 +
  128 +static void prep_set_irq(void *pic, int irq_num, int level)
  129 +{
  130 + int pic_irq_num;
  131 + prep_irq_levels[irq_num] = level;
  132 + level |= prep_irq_levels[irq_num ^ 2];
  133 + pic_irq_num = (irq_num == 0 || irq_num == 2) ? 9 : 11;
  134 + pic_set_irq(pic_irq_num, level);
125 } 135 }
126 136
127 PCIBus *pci_prep_init(void) 137 PCIBus *pci_prep_init(void)
@@ -131,7 +141,7 @@ PCIBus *pci_prep_init(void) @@ -131,7 +141,7 @@ PCIBus *pci_prep_init(void)
131 int PPC_io_memory; 141 int PPC_io_memory;
132 142
133 s = qemu_mallocz(sizeof(PREPPCIState)); 143 s = qemu_mallocz(sizeof(PREPPCIState));
134 - s->bus = pci_register_bus(prep_set_irq, NULL, 0); 144 + s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0);
135 145
136 register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s); 146 register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
137 register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s); 147 register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
hw/unin_pci.c
@@ -140,9 +140,15 @@ static CPUReadMemoryFunc *pci_unin_read[] = { @@ -140,9 +140,15 @@ static CPUReadMemoryFunc *pci_unin_read[] = {
140 }; 140 };
141 #endif 141 #endif
142 142
143 -static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level) 143 +/* Don't know if this matches real hardware, but it agrees with OHW. */
  144 +static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num)
144 { 145 {
145 - openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level); 146 + return (irq_num + (pci_dev->devfn >> 3)) & 3;
  147 +}
  148 +
  149 +static void pci_unin_set_irq(void *pic, int irq_num, int level)
  150 +{
  151 + openpic_set_irq(pic, irq_num + 8, level);
146 } 152 }
147 153
148 PCIBus *pci_pmac_init(void *pic) 154 PCIBus *pci_pmac_init(void *pic)
@@ -154,7 +160,8 @@ PCIBus *pci_pmac_init(void *pic) @@ -154,7 +160,8 @@ PCIBus *pci_pmac_init(void *pic)
154 /* Use values found on a real PowerMac */ 160 /* Use values found on a real PowerMac */
155 /* Uninorth main bus */ 161 /* Uninorth main bus */
156 s = qemu_mallocz(sizeof(UNINState)); 162 s = qemu_mallocz(sizeof(UNINState));
157 - s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3); 163 + s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq,
  164 + pic, 11 << 3);
158 165
159 pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, 166 pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
160 pci_unin_main_config_write, s); 167 pci_unin_main_config_write, s);
hw/versatile_pci.c
@@ -79,7 +79,12 @@ static CPUReadMemoryFunc *pci_vpb_config_read[] = { @@ -79,7 +79,12 @@ static CPUReadMemoryFunc *pci_vpb_config_read[] = {
79 79
80 static int pci_vpb_irq; 80 static int pci_vpb_irq;
81 81
82 -static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level) 82 +static int pci_vpb_map_irq(PCIDevice *d, int irq_num)
  83 +{
  84 + return irq_num;
  85 +}
  86 +
  87 +static void pci_vpb_set_irq(void *pic, int irq_num, int level)
83 { 88 {
84 pic_set_irq_new(pic, pci_vpb_irq + irq_num, level); 89 pic_set_irq_new(pic, pci_vpb_irq + irq_num, level);
85 } 90 }
@@ -100,7 +105,7 @@ PCIBus *pci_vpb_init(void *pic, int irq, int realview) @@ -100,7 +105,7 @@ PCIBus *pci_vpb_init(void *pic, int irq, int realview)
100 base = 0x40000000; 105 base = 0x40000000;
101 name = "Versatile/PB PCI Controller"; 106 name = "Versatile/PB PCI Controller";
102 } 107 }
103 - s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3); 108 + s = pci_register_bus(pci_vpb_set_irq, pci_vpb_map_irq, pic, 11 << 3);
104 /* ??? Register memory space. */ 109 /* ??? Register memory space. */
105 110
106 mem_config = cpu_register_io_memory(0, pci_vpb_config_read, 111 mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
@@ -733,6 +733,9 @@ struct PCIDevice { @@ -733,6 +733,9 @@ struct PCIDevice {
733 PCIConfigWriteFunc *config_write; 733 PCIConfigWriteFunc *config_write;
734 /* ??? This is a PC-specific hack, and should be removed. */ 734 /* ??? This is a PC-specific hack, and should be removed. */
735 int irq_index; 735 int irq_index;
  736 +
  737 + /* Current IRQ levels. Used internally by the generic PCI code. */
  738 + int irq_state[4];
736 }; 739 };
737 740
738 PCIDevice *pci_register_device(PCIBus *bus, const char *name, 741 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -753,9 +756,10 @@ void pci_default_write_config(PCIDevice *d, @@ -753,9 +756,10 @@ void pci_default_write_config(PCIDevice *d,
753 void pci_device_save(PCIDevice *s, QEMUFile *f); 756 void pci_device_save(PCIDevice *s, QEMUFile *f);
754 int pci_device_load(PCIDevice *s, QEMUFile *f); 757 int pci_device_load(PCIDevice *s, QEMUFile *f);
755 758
756 -typedef void (*pci_set_irq_fn)(PCIDevice *pci_dev, void *pic,  
757 - int irq_num, int level);  
758 -PCIBus *pci_register_bus(pci_set_irq_fn set_irq, void *pic, int devfn_min); 759 +typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level);
  760 +typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
  761 +PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
  762 + void *pic, int devfn_min);
759 763
760 void pci_nic_init(PCIBus *bus, NICInfo *nd); 764 void pci_nic_init(PCIBus *bus, NICInfo *nd);
761 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len); 765 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);