diff options
author | Corey Minyard <cminyard@mvista.com> | 2017-09-13 00:24:30 -0400 |
---|---|---|
committer | Corey Minyard <cminyard@mvista.com> | 2017-09-28 13:26:00 -0400 |
commit | 58e2763553cb837b879d4a2934094e152e7daf27 (patch) | |
tree | c7cfd0c210528fcb22cca63bdc1ce7a68b5c3559 | |
parent | d1a6791323b810ce9136a58d95c6e0e455313388 (diff) |
ipmi_si: Move port and mem I/O handling to their own files
Signed-off-by: Corey Minyard <cminyard@mvista.com>
-rw-r--r-- | drivers/char/ipmi/Makefile | 3 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si.h | 3 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_intf.c | 256 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_mem_io.c | 144 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_si_port_io.c | 112 |
5 files changed, 263 insertions, 255 deletions
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 3c01149e7d36..312396c1a8e5 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ | 5 | ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o \ |
6 | ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o | 6 | ipmi_si_hotmod.o ipmi_si_hardcode.o ipmi_si_platform.o \ |
7 | ipmi_si_port_io.o ipmi_si_mem_io.o | ||
7 | ifdef CONFIG_PCI | 8 | ifdef CONFIG_PCI |
8 | ipmi_si-y += ipmi_si_pci.o | 9 | ipmi_si-y += ipmi_si_pci.o |
9 | endif | 10 | endif |
diff --git a/drivers/char/ipmi/ipmi_si.h b/drivers/char/ipmi/ipmi_si.h index f3530d60db05..17ce5f7b89ab 100644 --- a/drivers/char/ipmi/ipmi_si.h +++ b/drivers/char/ipmi/ipmi_si.h | |||
@@ -44,3 +44,6 @@ void ipmi_si_parisc_shutdown(void); | |||
44 | static inline void ipmi_si_parisc_init(void) { } | 44 | static inline void ipmi_si_parisc_init(void) { } |
45 | static inline void ipmi_si_parisc_shutdown(void) { } | 45 | static inline void ipmi_si_parisc_shutdown(void) { } |
46 | #endif | 46 | #endif |
47 | |||
48 | int ipmi_si_port_setup(struct si_sm_io *io); | ||
49 | int ipmi_si_mem_setup(struct si_sm_io *io); | ||
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 801ca241b34c..d24cd5de09d0 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
@@ -49,7 +49,6 @@ | |||
49 | #include <linux/slab.h> | 49 | #include <linux/slab.h> |
50 | #include <linux/delay.h> | 50 | #include <linux/delay.h> |
51 | #include <linux/list.h> | 51 | #include <linux/list.h> |
52 | #include <linux/ioport.h> | ||
53 | #include <linux/notifier.h> | 52 | #include <linux/notifier.h> |
54 | #include <linux/mutex.h> | 53 | #include <linux/mutex.h> |
55 | #include <linux/kthread.h> | 54 | #include <linux/kthread.h> |
@@ -58,7 +57,6 @@ | |||
58 | #include <linux/rcupdate.h> | 57 | #include <linux/rcupdate.h> |
59 | #include <linux/ipmi.h> | 58 | #include <linux/ipmi.h> |
60 | #include <linux/ipmi_smi.h> | 59 | #include <linux/ipmi_smi.h> |
61 | #include <asm/io.h> | ||
62 | #include "ipmi_si.h" | 60 | #include "ipmi_si.h" |
63 | #include <linux/string.h> | 61 | #include <linux/string.h> |
64 | #include <linux/ctype.h> | 62 | #include <linux/ctype.h> |
@@ -1304,256 +1302,6 @@ int ipmi_std_irq_setup(struct si_sm_io *io) | |||
1304 | return rv; | 1302 | return rv; |
1305 | } | 1303 | } |
1306 | 1304 | ||
1307 | static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) | ||
1308 | { | ||
1309 | unsigned int addr = io->addr_data; | ||
1310 | |||
1311 | return inb(addr + (offset * io->regspacing)); | ||
1312 | } | ||
1313 | |||
1314 | static void port_outb(const struct si_sm_io *io, unsigned int offset, | ||
1315 | unsigned char b) | ||
1316 | { | ||
1317 | unsigned int addr = io->addr_data; | ||
1318 | |||
1319 | outb(b, addr + (offset * io->regspacing)); | ||
1320 | } | ||
1321 | |||
1322 | static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) | ||
1323 | { | ||
1324 | unsigned int addr = io->addr_data; | ||
1325 | |||
1326 | return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; | ||
1327 | } | ||
1328 | |||
1329 | static void port_outw(const struct si_sm_io *io, unsigned int offset, | ||
1330 | unsigned char b) | ||
1331 | { | ||
1332 | unsigned int addr = io->addr_data; | ||
1333 | |||
1334 | outw(b << io->regshift, addr + (offset * io->regspacing)); | ||
1335 | } | ||
1336 | |||
1337 | static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) | ||
1338 | { | ||
1339 | unsigned int addr = io->addr_data; | ||
1340 | |||
1341 | return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; | ||
1342 | } | ||
1343 | |||
1344 | static void port_outl(const struct si_sm_io *io, unsigned int offset, | ||
1345 | unsigned char b) | ||
1346 | { | ||
1347 | unsigned int addr = io->addr_data; | ||
1348 | |||
1349 | outl(b << io->regshift, addr+(offset * io->regspacing)); | ||
1350 | } | ||
1351 | |||
1352 | static void port_cleanup(struct si_sm_io *io) | ||
1353 | { | ||
1354 | unsigned int addr = io->addr_data; | ||
1355 | int idx; | ||
1356 | |||
1357 | if (addr) { | ||
1358 | for (idx = 0; idx < io->io_size; idx++) | ||
1359 | release_region(addr + idx * io->regspacing, | ||
1360 | io->regsize); | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | static int port_setup(struct si_sm_io *io) | ||
1365 | { | ||
1366 | unsigned int addr = io->addr_data; | ||
1367 | int idx; | ||
1368 | |||
1369 | if (!addr) | ||
1370 | return -ENODEV; | ||
1371 | |||
1372 | io->io_cleanup = port_cleanup; | ||
1373 | |||
1374 | /* | ||
1375 | * Figure out the actual inb/inw/inl/etc routine to use based | ||
1376 | * upon the register size. | ||
1377 | */ | ||
1378 | switch (io->regsize) { | ||
1379 | case 1: | ||
1380 | io->inputb = port_inb; | ||
1381 | io->outputb = port_outb; | ||
1382 | break; | ||
1383 | case 2: | ||
1384 | io->inputb = port_inw; | ||
1385 | io->outputb = port_outw; | ||
1386 | break; | ||
1387 | case 4: | ||
1388 | io->inputb = port_inl; | ||
1389 | io->outputb = port_outl; | ||
1390 | break; | ||
1391 | default: | ||
1392 | dev_warn(io->dev, "Invalid register size: %d\n", | ||
1393 | io->regsize); | ||
1394 | return -EINVAL; | ||
1395 | } | ||
1396 | |||
1397 | /* | ||
1398 | * Some BIOSes reserve disjoint I/O regions in their ACPI | ||
1399 | * tables. This causes problems when trying to register the | ||
1400 | * entire I/O region. Therefore we must register each I/O | ||
1401 | * port separately. | ||
1402 | */ | ||
1403 | for (idx = 0; idx < io->io_size; idx++) { | ||
1404 | if (request_region(addr + idx * io->regspacing, | ||
1405 | io->regsize, DEVICE_NAME) == NULL) { | ||
1406 | /* Undo allocations */ | ||
1407 | while (idx--) | ||
1408 | release_region(addr + idx * io->regspacing, | ||
1409 | io->regsize); | ||
1410 | return -EIO; | ||
1411 | } | ||
1412 | } | ||
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | static unsigned char intf_mem_inb(const struct si_sm_io *io, | ||
1417 | unsigned int offset) | ||
1418 | { | ||
1419 | return readb((io->addr)+(offset * io->regspacing)); | ||
1420 | } | ||
1421 | |||
1422 | static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, | ||
1423 | unsigned char b) | ||
1424 | { | ||
1425 | writeb(b, (io->addr)+(offset * io->regspacing)); | ||
1426 | } | ||
1427 | |||
1428 | static unsigned char intf_mem_inw(const struct si_sm_io *io, | ||
1429 | unsigned int offset) | ||
1430 | { | ||
1431 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
1432 | & 0xff; | ||
1433 | } | ||
1434 | |||
1435 | static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, | ||
1436 | unsigned char b) | ||
1437 | { | ||
1438 | writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
1439 | } | ||
1440 | |||
1441 | static unsigned char intf_mem_inl(const struct si_sm_io *io, | ||
1442 | unsigned int offset) | ||
1443 | { | ||
1444 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
1445 | & 0xff; | ||
1446 | } | ||
1447 | |||
1448 | static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, | ||
1449 | unsigned char b) | ||
1450 | { | ||
1451 | writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
1452 | } | ||
1453 | |||
1454 | #ifdef readq | ||
1455 | static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) | ||
1456 | { | ||
1457 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
1458 | & 0xff; | ||
1459 | } | ||
1460 | |||
1461 | static void mem_outq(const struct si_sm_io *io, unsigned int offset, | ||
1462 | unsigned char b) | ||
1463 | { | ||
1464 | writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
1465 | } | ||
1466 | #endif | ||
1467 | |||
1468 | static void mem_region_cleanup(struct si_sm_io *io, int num) | ||
1469 | { | ||
1470 | unsigned long addr = io->addr_data; | ||
1471 | int idx; | ||
1472 | |||
1473 | for (idx = 0; idx < num; idx++) | ||
1474 | release_mem_region(addr + idx * io->regspacing, | ||
1475 | io->regsize); | ||
1476 | } | ||
1477 | |||
1478 | static void mem_cleanup(struct si_sm_io *io) | ||
1479 | { | ||
1480 | if (io->addr) { | ||
1481 | iounmap(io->addr); | ||
1482 | mem_region_cleanup(io, io->io_size); | ||
1483 | } | ||
1484 | } | ||
1485 | |||
1486 | static int mem_setup(struct si_sm_io *io) | ||
1487 | { | ||
1488 | unsigned long addr = io->addr_data; | ||
1489 | int mapsize, idx; | ||
1490 | |||
1491 | if (!addr) | ||
1492 | return -ENODEV; | ||
1493 | |||
1494 | io->io_cleanup = mem_cleanup; | ||
1495 | |||
1496 | /* | ||
1497 | * Figure out the actual readb/readw/readl/etc routine to use based | ||
1498 | * upon the register size. | ||
1499 | */ | ||
1500 | switch (io->regsize) { | ||
1501 | case 1: | ||
1502 | io->inputb = intf_mem_inb; | ||
1503 | io->outputb = intf_mem_outb; | ||
1504 | break; | ||
1505 | case 2: | ||
1506 | io->inputb = intf_mem_inw; | ||
1507 | io->outputb = intf_mem_outw; | ||
1508 | break; | ||
1509 | case 4: | ||
1510 | io->inputb = intf_mem_inl; | ||
1511 | io->outputb = intf_mem_outl; | ||
1512 | break; | ||
1513 | #ifdef readq | ||
1514 | case 8: | ||
1515 | io->inputb = mem_inq; | ||
1516 | io->outputb = mem_outq; | ||
1517 | break; | ||
1518 | #endif | ||
1519 | default: | ||
1520 | dev_warn(io->dev, "Invalid register size: %d\n", | ||
1521 | io->regsize); | ||
1522 | return -EINVAL; | ||
1523 | } | ||
1524 | |||
1525 | /* | ||
1526 | * Some BIOSes reserve disjoint memory regions in their ACPI | ||
1527 | * tables. This causes problems when trying to request the | ||
1528 | * entire region. Therefore we must request each register | ||
1529 | * separately. | ||
1530 | */ | ||
1531 | for (idx = 0; idx < io->io_size; idx++) { | ||
1532 | if (request_mem_region(addr + idx * io->regspacing, | ||
1533 | io->regsize, DEVICE_NAME) == NULL) { | ||
1534 | /* Undo allocations */ | ||
1535 | mem_region_cleanup(io, idx); | ||
1536 | return -EIO; | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | /* | ||
1541 | * Calculate the total amount of memory to claim. This is an | ||
1542 | * unusual looking calculation, but it avoids claiming any | ||
1543 | * more memory than it has to. It will claim everything | ||
1544 | * between the first address to the end of the last full | ||
1545 | * register. | ||
1546 | */ | ||
1547 | mapsize = ((io->io_size * io->regspacing) | ||
1548 | - (io->regspacing - io->regsize)); | ||
1549 | io->addr = ioremap(addr, mapsize); | ||
1550 | if (io->addr == NULL) { | ||
1551 | mem_region_cleanup(io, io->io_size); | ||
1552 | return -EIO; | ||
1553 | } | ||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | static struct smi_info *smi_info_alloc(void) | 1305 | static struct smi_info *smi_info_alloc(void) |
1558 | { | 1306 | { |
1559 | struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); | 1307 | struct smi_info *info = kzalloc(sizeof(*info), GFP_KERNEL); |
@@ -2146,9 +1894,9 @@ int ipmi_si_add_smi(struct si_sm_io *io) | |||
2146 | 1894 | ||
2147 | if (!io->io_setup) { | 1895 | if (!io->io_setup) { |
2148 | if (io->addr_type == IPMI_IO_ADDR_SPACE) { | 1896 | if (io->addr_type == IPMI_IO_ADDR_SPACE) { |
2149 | io->io_setup = port_setup; | 1897 | io->io_setup = ipmi_si_port_setup; |
2150 | } else if (io->addr_type == IPMI_MEM_ADDR_SPACE) { | 1898 | } else if (io->addr_type == IPMI_MEM_ADDR_SPACE) { |
2151 | io->io_setup = mem_setup; | 1899 | io->io_setup = ipmi_si_mem_setup; |
2152 | } else { | 1900 | } else { |
2153 | return -EINVAL; | 1901 | return -EINVAL; |
2154 | } | 1902 | } |
diff --git a/drivers/char/ipmi/ipmi_si_mem_io.c b/drivers/char/ipmi/ipmi_si_mem_io.c new file mode 100644 index 000000000000..8796396ecd0f --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_mem_io.c | |||
@@ -0,0 +1,144 @@ | |||
1 | |||
2 | #include <linux/io.h> | ||
3 | #include "ipmi_si.h" | ||
4 | |||
5 | static unsigned char intf_mem_inb(const struct si_sm_io *io, | ||
6 | unsigned int offset) | ||
7 | { | ||
8 | return readb((io->addr)+(offset * io->regspacing)); | ||
9 | } | ||
10 | |||
11 | static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, | ||
12 | unsigned char b) | ||
13 | { | ||
14 | writeb(b, (io->addr)+(offset * io->regspacing)); | ||
15 | } | ||
16 | |||
17 | static unsigned char intf_mem_inw(const struct si_sm_io *io, | ||
18 | unsigned int offset) | ||
19 | { | ||
20 | return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
21 | & 0xff; | ||
22 | } | ||
23 | |||
24 | static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, | ||
25 | unsigned char b) | ||
26 | { | ||
27 | writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
28 | } | ||
29 | |||
30 | static unsigned char intf_mem_inl(const struct si_sm_io *io, | ||
31 | unsigned int offset) | ||
32 | { | ||
33 | return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
34 | & 0xff; | ||
35 | } | ||
36 | |||
37 | static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, | ||
38 | unsigned char b) | ||
39 | { | ||
40 | writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
41 | } | ||
42 | |||
43 | #ifdef readq | ||
44 | static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) | ||
45 | { | ||
46 | return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) | ||
47 | & 0xff; | ||
48 | } | ||
49 | |||
50 | static void mem_outq(const struct si_sm_io *io, unsigned int offset, | ||
51 | unsigned char b) | ||
52 | { | ||
53 | writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | static void mem_region_cleanup(struct si_sm_io *io, int num) | ||
58 | { | ||
59 | unsigned long addr = io->addr_data; | ||
60 | int idx; | ||
61 | |||
62 | for (idx = 0; idx < num; idx++) | ||
63 | release_mem_region(addr + idx * io->regspacing, | ||
64 | io->regsize); | ||
65 | } | ||
66 | |||
67 | static void mem_cleanup(struct si_sm_io *io) | ||
68 | { | ||
69 | if (io->addr) { | ||
70 | iounmap(io->addr); | ||
71 | mem_region_cleanup(io, io->io_size); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | int ipmi_si_mem_setup(struct si_sm_io *io) | ||
76 | { | ||
77 | unsigned long addr = io->addr_data; | ||
78 | int mapsize, idx; | ||
79 | |||
80 | if (!addr) | ||
81 | return -ENODEV; | ||
82 | |||
83 | io->io_cleanup = mem_cleanup; | ||
84 | |||
85 | /* | ||
86 | * Figure out the actual readb/readw/readl/etc routine to use based | ||
87 | * upon the register size. | ||
88 | */ | ||
89 | switch (io->regsize) { | ||
90 | case 1: | ||
91 | io->inputb = intf_mem_inb; | ||
92 | io->outputb = intf_mem_outb; | ||
93 | break; | ||
94 | case 2: | ||
95 | io->inputb = intf_mem_inw; | ||
96 | io->outputb = intf_mem_outw; | ||
97 | break; | ||
98 | case 4: | ||
99 | io->inputb = intf_mem_inl; | ||
100 | io->outputb = intf_mem_outl; | ||
101 | break; | ||
102 | #ifdef readq | ||
103 | case 8: | ||
104 | io->inputb = mem_inq; | ||
105 | io->outputb = mem_outq; | ||
106 | break; | ||
107 | #endif | ||
108 | default: | ||
109 | dev_warn(io->dev, "Invalid register size: %d\n", | ||
110 | io->regsize); | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Some BIOSes reserve disjoint memory regions in their ACPI | ||
116 | * tables. This causes problems when trying to request the | ||
117 | * entire region. Therefore we must request each register | ||
118 | * separately. | ||
119 | */ | ||
120 | for (idx = 0; idx < io->io_size; idx++) { | ||
121 | if (request_mem_region(addr + idx * io->regspacing, | ||
122 | io->regsize, DEVICE_NAME) == NULL) { | ||
123 | /* Undo allocations */ | ||
124 | mem_region_cleanup(io, idx); | ||
125 | return -EIO; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Calculate the total amount of memory to claim. This is an | ||
131 | * unusual looking calculation, but it avoids claiming any | ||
132 | * more memory than it has to. It will claim everything | ||
133 | * between the first address to the end of the last full | ||
134 | * register. | ||
135 | */ | ||
136 | mapsize = ((io->io_size * io->regspacing) | ||
137 | - (io->regspacing - io->regsize)); | ||
138 | io->addr = ioremap(addr, mapsize); | ||
139 | if (io->addr == NULL) { | ||
140 | mem_region_cleanup(io, io->io_size); | ||
141 | return -EIO; | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
diff --git a/drivers/char/ipmi/ipmi_si_port_io.c b/drivers/char/ipmi/ipmi_si_port_io.c new file mode 100644 index 000000000000..e5ce174fbeeb --- /dev/null +++ b/drivers/char/ipmi/ipmi_si_port_io.c | |||
@@ -0,0 +1,112 @@ | |||
1 | |||
2 | #include <linux/io.h> | ||
3 | #include "ipmi_si.h" | ||
4 | |||
5 | static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) | ||
6 | { | ||
7 | unsigned int addr = io->addr_data; | ||
8 | |||
9 | return inb(addr + (offset * io->regspacing)); | ||
10 | } | ||
11 | |||
12 | static void port_outb(const struct si_sm_io *io, unsigned int offset, | ||
13 | unsigned char b) | ||
14 | { | ||
15 | unsigned int addr = io->addr_data; | ||
16 | |||
17 | outb(b, addr + (offset * io->regspacing)); | ||
18 | } | ||
19 | |||
20 | static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) | ||
21 | { | ||
22 | unsigned int addr = io->addr_data; | ||
23 | |||
24 | return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; | ||
25 | } | ||
26 | |||
27 | static void port_outw(const struct si_sm_io *io, unsigned int offset, | ||
28 | unsigned char b) | ||
29 | { | ||
30 | unsigned int addr = io->addr_data; | ||
31 | |||
32 | outw(b << io->regshift, addr + (offset * io->regspacing)); | ||
33 | } | ||
34 | |||
35 | static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) | ||
36 | { | ||
37 | unsigned int addr = io->addr_data; | ||
38 | |||
39 | return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; | ||
40 | } | ||
41 | |||
42 | static void port_outl(const struct si_sm_io *io, unsigned int offset, | ||
43 | unsigned char b) | ||
44 | { | ||
45 | unsigned int addr = io->addr_data; | ||
46 | |||
47 | outl(b << io->regshift, addr+(offset * io->regspacing)); | ||
48 | } | ||
49 | |||
50 | static void port_cleanup(struct si_sm_io *io) | ||
51 | { | ||
52 | unsigned int addr = io->addr_data; | ||
53 | int idx; | ||
54 | |||
55 | if (addr) { | ||
56 | for (idx = 0; idx < io->io_size; idx++) | ||
57 | release_region(addr + idx * io->regspacing, | ||
58 | io->regsize); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | int ipmi_si_port_setup(struct si_sm_io *io) | ||
63 | { | ||
64 | unsigned int addr = io->addr_data; | ||
65 | int idx; | ||
66 | |||
67 | if (!addr) | ||
68 | return -ENODEV; | ||
69 | |||
70 | io->io_cleanup = port_cleanup; | ||
71 | |||
72 | /* | ||
73 | * Figure out the actual inb/inw/inl/etc routine to use based | ||
74 | * upon the register size. | ||
75 | */ | ||
76 | switch (io->regsize) { | ||
77 | case 1: | ||
78 | io->inputb = port_inb; | ||
79 | io->outputb = port_outb; | ||
80 | break; | ||
81 | case 2: | ||
82 | io->inputb = port_inw; | ||
83 | io->outputb = port_outw; | ||
84 | break; | ||
85 | case 4: | ||
86 | io->inputb = port_inl; | ||
87 | io->outputb = port_outl; | ||
88 | break; | ||
89 | default: | ||
90 | dev_warn(io->dev, "Invalid register size: %d\n", | ||
91 | io->regsize); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * Some BIOSes reserve disjoint I/O regions in their ACPI | ||
97 | * tables. This causes problems when trying to register the | ||
98 | * entire I/O region. Therefore we must register each I/O | ||
99 | * port separately. | ||
100 | */ | ||
101 | for (idx = 0; idx < io->io_size; idx++) { | ||
102 | if (request_region(addr + idx * io->regspacing, | ||
103 | io->regsize, DEVICE_NAME) == NULL) { | ||
104 | /* Undo allocations */ | ||
105 | while (idx--) | ||
106 | release_region(addr + idx * io->regspacing, | ||
107 | io->regsize); | ||
108 | return -EIO; | ||
109 | } | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||