xref: /aosp_15_r20/external/pciutils/lib/aix-device.c (revision c2e0c6b56a71da9abe8df5c8348fb3eb5c2c9251)
1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker  *	The PCI Library -- AIX /dev/pci[0-n] access
3*c2e0c6b5SAndroid Build Coastguard Worker  *
4*c2e0c6b5SAndroid Build Coastguard Worker  *	Copyright (c) 1999 Jari Kirma <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker  *
6*c2e0c6b5SAndroid Build Coastguard Worker  *	Can be freely distributed and used under the terms of the GNU GPL v2+.
7*c2e0c6b5SAndroid Build Coastguard Worker  *
8*c2e0c6b5SAndroid Build Coastguard Worker  *	SPDX-License-Identifier: GPL-2.0-or-later
9*c2e0c6b5SAndroid Build Coastguard Worker  */
10*c2e0c6b5SAndroid Build Coastguard Worker 
11*c2e0c6b5SAndroid Build Coastguard Worker /*
12*c2e0c6b5SAndroid Build Coastguard Worker  *      Read functionality of this driver is briefly tested, and seems
13*c2e0c6b5SAndroid Build Coastguard Worker  *      to supply basic information correctly, but I promise no more.
14*c2e0c6b5SAndroid Build Coastguard Worker  */
15*c2e0c6b5SAndroid Build Coastguard Worker 
16*c2e0c6b5SAndroid Build Coastguard Worker #include <stdio.h>
17*c2e0c6b5SAndroid Build Coastguard Worker #include <stdlib.h>
18*c2e0c6b5SAndroid Build Coastguard Worker #include <string.h>
19*c2e0c6b5SAndroid Build Coastguard Worker #include <unistd.h>
20*c2e0c6b5SAndroid Build Coastguard Worker #include <fcntl.h>
21*c2e0c6b5SAndroid Build Coastguard Worker 
22*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/types.h>
23*c2e0c6b5SAndroid Build Coastguard Worker #include <sys/mdio.h>
24*c2e0c6b5SAndroid Build Coastguard Worker 
25*c2e0c6b5SAndroid Build Coastguard Worker #include "internal.h"
26*c2e0c6b5SAndroid Build Coastguard Worker 
27*c2e0c6b5SAndroid Build Coastguard Worker #define AIX_LSDEV_CMD "/usr/sbin/lsdev -C -c bus -t pci\\* -S available -F name"
28*c2e0c6b5SAndroid Build Coastguard Worker #define AIX_ODMGET_CMD \
29*c2e0c6b5SAndroid Build Coastguard Worker   "/usr/bin/odmget -q 'name=%s and attribute=bus_number' CuAt | \
30*c2e0c6b5SAndroid Build Coastguard Worker    /usr/bin/awk '$1 == \"value\" { print $3 }'"
31*c2e0c6b5SAndroid Build Coastguard Worker 
32*c2e0c6b5SAndroid Build Coastguard Worker 
33*c2e0c6b5SAndroid Build Coastguard Worker /* AIX PCI bus device information */
34*c2e0c6b5SAndroid Build Coastguard Worker 
35*c2e0c6b5SAndroid Build Coastguard Worker typedef struct aix_pci_bus {
36*c2e0c6b5SAndroid Build Coastguard Worker     char *bus_name;
37*c2e0c6b5SAndroid Build Coastguard Worker     int   bus_number;
38*c2e0c6b5SAndroid Build Coastguard Worker     int   bus_fd;
39*c2e0c6b5SAndroid Build Coastguard Worker } aix_pci_bus;
40*c2e0c6b5SAndroid Build Coastguard Worker 
41*c2e0c6b5SAndroid Build Coastguard Worker #define PCI_BUS_MAX 16		/* arbitrary choice */
42*c2e0c6b5SAndroid Build Coastguard Worker static aix_pci_bus pci_buses[PCI_BUS_MAX];
43*c2e0c6b5SAndroid Build Coastguard Worker static int pci_bus_count = 0;
44*c2e0c6b5SAndroid Build Coastguard Worker 
45*c2e0c6b5SAndroid Build Coastguard Worker 
46*c2e0c6b5SAndroid Build Coastguard Worker /* Utility Routines */
47*c2e0c6b5SAndroid Build Coastguard Worker 
48*c2e0c6b5SAndroid Build Coastguard Worker static aix_pci_bus *
aix_find_bus(struct pci_access * a,int bus_number)49*c2e0c6b5SAndroid Build Coastguard Worker aix_find_bus(struct pci_access *a, int bus_number)
50*c2e0c6b5SAndroid Build Coastguard Worker {
51*c2e0c6b5SAndroid Build Coastguard Worker   int i;
52*c2e0c6b5SAndroid Build Coastguard Worker 
53*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < pci_bus_count; i++)
54*c2e0c6b5SAndroid Build Coastguard Worker     {
55*c2e0c6b5SAndroid Build Coastguard Worker       if (pci_buses[i].bus_number == bus_number)
56*c2e0c6b5SAndroid Build Coastguard Worker         {
57*c2e0c6b5SAndroid Build Coastguard Worker           return &pci_buses[i];
58*c2e0c6b5SAndroid Build Coastguard Worker         }
59*c2e0c6b5SAndroid Build Coastguard Worker     }
60*c2e0c6b5SAndroid Build Coastguard Worker 
61*c2e0c6b5SAndroid Build Coastguard Worker   a->error("aix_find_bus: bus number %d not found", bus_number);
62*c2e0c6b5SAndroid Build Coastguard Worker }
63*c2e0c6b5SAndroid Build Coastguard Worker 
64*c2e0c6b5SAndroid Build Coastguard Worker static int
aix_bus_open(struct pci_dev * d)65*c2e0c6b5SAndroid Build Coastguard Worker aix_bus_open(struct pci_dev *d)
66*c2e0c6b5SAndroid Build Coastguard Worker {
67*c2e0c6b5SAndroid Build Coastguard Worker   struct pci_access *a = d->access;
68*c2e0c6b5SAndroid Build Coastguard Worker   aix_pci_bus *bp = aix_find_bus(a, d->bus);
69*c2e0c6b5SAndroid Build Coastguard Worker 
70*c2e0c6b5SAndroid Build Coastguard Worker   if (bp->bus_fd < 0)
71*c2e0c6b5SAndroid Build Coastguard Worker     {
72*c2e0c6b5SAndroid Build Coastguard Worker       char devbuf[256];
73*c2e0c6b5SAndroid Build Coastguard Worker       int mode = a->writeable ? O_RDWR : O_RDONLY;
74*c2e0c6b5SAndroid Build Coastguard Worker 
75*c2e0c6b5SAndroid Build Coastguard Worker       snprintf(devbuf, sizeof (devbuf), "/dev/%s", bp->bus_name);
76*c2e0c6b5SAndroid Build Coastguard Worker       bp->bus_fd = open(devbuf, mode, 0);
77*c2e0c6b5SAndroid Build Coastguard Worker       if (bp->bus_fd < 0)
78*c2e0c6b5SAndroid Build Coastguard Worker 	a->error("aix_open_bus: %s open failed", devbuf);
79*c2e0c6b5SAndroid Build Coastguard Worker     }
80*c2e0c6b5SAndroid Build Coastguard Worker 
81*c2e0c6b5SAndroid Build Coastguard Worker   return bp->bus_fd;
82*c2e0c6b5SAndroid Build Coastguard Worker }
83*c2e0c6b5SAndroid Build Coastguard Worker 
84*c2e0c6b5SAndroid Build Coastguard Worker static int
aix_bus_number(char * name)85*c2e0c6b5SAndroid Build Coastguard Worker aix_bus_number(char *name)
86*c2e0c6b5SAndroid Build Coastguard Worker {
87*c2e0c6b5SAndroid Build Coastguard Worker   int bus_number;
88*c2e0c6b5SAndroid Build Coastguard Worker   FILE *odmget_pipe;
89*c2e0c6b5SAndroid Build Coastguard Worker   char command[256];
90*c2e0c6b5SAndroid Build Coastguard Worker   char buf[256];
91*c2e0c6b5SAndroid Build Coastguard Worker   char *bp;
92*c2e0c6b5SAndroid Build Coastguard Worker   char *ep;
93*c2e0c6b5SAndroid Build Coastguard Worker 
94*c2e0c6b5SAndroid Build Coastguard Worker   snprintf(command, sizeof (command), AIX_ODMGET_CMD, name);
95*c2e0c6b5SAndroid Build Coastguard Worker   odmget_pipe = popen(command, "r");
96*c2e0c6b5SAndroid Build Coastguard Worker   if (odmget_pipe == NULL)
97*c2e0c6b5SAndroid Build Coastguard Worker     {
98*c2e0c6b5SAndroid Build Coastguard Worker       /* popen failed */
99*c2e0c6b5SAndroid Build Coastguard Worker       return -1;
100*c2e0c6b5SAndroid Build Coastguard Worker     }
101*c2e0c6b5SAndroid Build Coastguard Worker 
102*c2e0c6b5SAndroid Build Coastguard Worker   if (fgets(buf, sizeof (buf) - 1, odmget_pipe) != NULL)
103*c2e0c6b5SAndroid Build Coastguard Worker     {
104*c2e0c6b5SAndroid Build Coastguard Worker       bp = buf + 1;	/* skip leading double quote */
105*c2e0c6b5SAndroid Build Coastguard Worker       bus_number = strtol(bp, &ep, 0);
106*c2e0c6b5SAndroid Build Coastguard Worker       if (bp == ep)
107*c2e0c6b5SAndroid Build Coastguard Worker         {
108*c2e0c6b5SAndroid Build Coastguard Worker           /* strtol failed */
109*c2e0c6b5SAndroid Build Coastguard Worker           bus_number = -1;
110*c2e0c6b5SAndroid Build Coastguard Worker         }
111*c2e0c6b5SAndroid Build Coastguard Worker     }
112*c2e0c6b5SAndroid Build Coastguard Worker   else
113*c2e0c6b5SAndroid Build Coastguard Worker     {
114*c2e0c6b5SAndroid Build Coastguard Worker       /* first PCI bus_number is not recorded in ODM CuAt; default to 0 */
115*c2e0c6b5SAndroid Build Coastguard Worker       bus_number = 0;
116*c2e0c6b5SAndroid Build Coastguard Worker     }
117*c2e0c6b5SAndroid Build Coastguard Worker 
118*c2e0c6b5SAndroid Build Coastguard Worker   (void) pclose(odmget_pipe);
119*c2e0c6b5SAndroid Build Coastguard Worker 
120*c2e0c6b5SAndroid Build Coastguard Worker   return bus_number;
121*c2e0c6b5SAndroid Build Coastguard Worker }
122*c2e0c6b5SAndroid Build Coastguard Worker 
123*c2e0c6b5SAndroid Build Coastguard Worker 
124*c2e0c6b5SAndroid Build Coastguard Worker /* Method entries */
125*c2e0c6b5SAndroid Build Coastguard Worker 
126*c2e0c6b5SAndroid Build Coastguard Worker static int
aix_detect(struct pci_access * a)127*c2e0c6b5SAndroid Build Coastguard Worker aix_detect(struct pci_access *a)
128*c2e0c6b5SAndroid Build Coastguard Worker {
129*c2e0c6b5SAndroid Build Coastguard Worker   int len;
130*c2e0c6b5SAndroid Build Coastguard Worker   int mode = a->writeable ? W_OK : R_OK;
131*c2e0c6b5SAndroid Build Coastguard Worker   char *command = AIX_LSDEV_CMD;
132*c2e0c6b5SAndroid Build Coastguard Worker   FILE *lsdev_pipe;
133*c2e0c6b5SAndroid Build Coastguard Worker   char buf[256];
134*c2e0c6b5SAndroid Build Coastguard Worker   char *name;
135*c2e0c6b5SAndroid Build Coastguard Worker 
136*c2e0c6b5SAndroid Build Coastguard Worker   lsdev_pipe = popen(command, "r");
137*c2e0c6b5SAndroid Build Coastguard Worker   if (lsdev_pipe == NULL)
138*c2e0c6b5SAndroid Build Coastguard Worker     {
139*c2e0c6b5SAndroid Build Coastguard Worker       a->error("aix_config: popen(\"%s\") failed", command);
140*c2e0c6b5SAndroid Build Coastguard Worker     }
141*c2e0c6b5SAndroid Build Coastguard Worker 
142*c2e0c6b5SAndroid Build Coastguard Worker   while (fgets(buf, sizeof (buf) - 1, lsdev_pipe) != NULL)
143*c2e0c6b5SAndroid Build Coastguard Worker     {
144*c2e0c6b5SAndroid Build Coastguard Worker       len = strlen(buf);
145*c2e0c6b5SAndroid Build Coastguard Worker       while (buf[len-1] == '\n' || buf[len-1] == '\r')
146*c2e0c6b5SAndroid Build Coastguard Worker           len--;
147*c2e0c6b5SAndroid Build Coastguard Worker       buf[len] = '\0';				/* clobber the newline */
148*c2e0c6b5SAndroid Build Coastguard Worker 
149*c2e0c6b5SAndroid Build Coastguard Worker       name = (char *) pci_malloc(a, len + 1);
150*c2e0c6b5SAndroid Build Coastguard Worker       strcpy(name, buf);
151*c2e0c6b5SAndroid Build Coastguard Worker       pci_buses[pci_bus_count].bus_name = name;
152*c2e0c6b5SAndroid Build Coastguard Worker       pci_buses[pci_bus_count].bus_number = 0;
153*c2e0c6b5SAndroid Build Coastguard Worker       pci_buses[pci_bus_count].bus_fd = -1;
154*c2e0c6b5SAndroid Build Coastguard Worker       if (!pci_bus_count)
155*c2e0c6b5SAndroid Build Coastguard Worker           a->debug("...using %s", name);
156*c2e0c6b5SAndroid Build Coastguard Worker       else
157*c2e0c6b5SAndroid Build Coastguard Worker           a->debug(", %s", name);
158*c2e0c6b5SAndroid Build Coastguard Worker       pci_bus_count++;
159*c2e0c6b5SAndroid Build Coastguard Worker       if (pci_bus_count >= PCI_BUS_MAX)
160*c2e0c6b5SAndroid Build Coastguard Worker           break;
161*c2e0c6b5SAndroid Build Coastguard Worker     }
162*c2e0c6b5SAndroid Build Coastguard Worker 
163*c2e0c6b5SAndroid Build Coastguard Worker   (void) pclose(lsdev_pipe);
164*c2e0c6b5SAndroid Build Coastguard Worker 
165*c2e0c6b5SAndroid Build Coastguard Worker   return pci_bus_count;
166*c2e0c6b5SAndroid Build Coastguard Worker }
167*c2e0c6b5SAndroid Build Coastguard Worker 
168*c2e0c6b5SAndroid Build Coastguard Worker static void
aix_init(struct pci_access * a)169*c2e0c6b5SAndroid Build Coastguard Worker aix_init(struct pci_access *a)
170*c2e0c6b5SAndroid Build Coastguard Worker {
171*c2e0c6b5SAndroid Build Coastguard Worker   char *name;
172*c2e0c6b5SAndroid Build Coastguard Worker   int i;
173*c2e0c6b5SAndroid Build Coastguard Worker 
174*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < pci_bus_count; i++)
175*c2e0c6b5SAndroid Build Coastguard Worker     {
176*c2e0c6b5SAndroid Build Coastguard Worker       name = pci_buses[i].bus_name;
177*c2e0c6b5SAndroid Build Coastguard Worker       pci_buses[i].bus_number = aix_bus_number(name);
178*c2e0c6b5SAndroid Build Coastguard Worker     }
179*c2e0c6b5SAndroid Build Coastguard Worker }
180*c2e0c6b5SAndroid Build Coastguard Worker 
181*c2e0c6b5SAndroid Build Coastguard Worker static void
aix_cleanup(struct pci_access * a)182*c2e0c6b5SAndroid Build Coastguard Worker aix_cleanup(struct pci_access *a)
183*c2e0c6b5SAndroid Build Coastguard Worker {
184*c2e0c6b5SAndroid Build Coastguard Worker   aix_pci_bus *bp;
185*c2e0c6b5SAndroid Build Coastguard Worker 
186*c2e0c6b5SAndroid Build Coastguard Worker   while (pci_bus_count-- > 0)
187*c2e0c6b5SAndroid Build Coastguard Worker     {
188*c2e0c6b5SAndroid Build Coastguard Worker       bp = &pci_buses[pci_bus_count];
189*c2e0c6b5SAndroid Build Coastguard Worker       (void) free(bp->bus_name);
190*c2e0c6b5SAndroid Build Coastguard Worker       if (bp->bus_fd >= 0)
191*c2e0c6b5SAndroid Build Coastguard Worker         {
192*c2e0c6b5SAndroid Build Coastguard Worker           (void) close(bp->bus_fd);
193*c2e0c6b5SAndroid Build Coastguard Worker           bp->bus_fd = -1;
194*c2e0c6b5SAndroid Build Coastguard Worker         }
195*c2e0c6b5SAndroid Build Coastguard Worker     }
196*c2e0c6b5SAndroid Build Coastguard Worker }
197*c2e0c6b5SAndroid Build Coastguard Worker 
198*c2e0c6b5SAndroid Build Coastguard Worker void
aix_scan(struct pci_access * a)199*c2e0c6b5SAndroid Build Coastguard Worker aix_scan(struct pci_access *a)
200*c2e0c6b5SAndroid Build Coastguard Worker {
201*c2e0c6b5SAndroid Build Coastguard Worker   int i;
202*c2e0c6b5SAndroid Build Coastguard Worker   int bus_number;
203*c2e0c6b5SAndroid Build Coastguard Worker   byte busmap[256];
204*c2e0c6b5SAndroid Build Coastguard Worker 
205*c2e0c6b5SAndroid Build Coastguard Worker   memset(busmap, 0, sizeof(busmap));
206*c2e0c6b5SAndroid Build Coastguard Worker   for (i = 0; i < pci_bus_count; i++)
207*c2e0c6b5SAndroid Build Coastguard Worker     {
208*c2e0c6b5SAndroid Build Coastguard Worker       bus_number = pci_buses[i].bus_number;
209*c2e0c6b5SAndroid Build Coastguard Worker       if (!busmap[bus_number])
210*c2e0c6b5SAndroid Build Coastguard Worker         {
211*c2e0c6b5SAndroid Build Coastguard Worker           pci_generic_scan_bus(a, busmap, 0, bus_number);
212*c2e0c6b5SAndroid Build Coastguard Worker         }
213*c2e0c6b5SAndroid Build Coastguard Worker     }
214*c2e0c6b5SAndroid Build Coastguard Worker }
215*c2e0c6b5SAndroid Build Coastguard Worker 
216*c2e0c6b5SAndroid Build Coastguard Worker static int
aix_read(struct pci_dev * d,int pos,byte * buf,int len)217*c2e0c6b5SAndroid Build Coastguard Worker aix_read(struct pci_dev *d, int pos, byte *buf, int len)
218*c2e0c6b5SAndroid Build Coastguard Worker {
219*c2e0c6b5SAndroid Build Coastguard Worker   struct mdio mdio;
220*c2e0c6b5SAndroid Build Coastguard Worker   int fd;
221*c2e0c6b5SAndroid Build Coastguard Worker 
222*c2e0c6b5SAndroid Build Coastguard Worker   if (d->domain || pos + len > 256)
223*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
224*c2e0c6b5SAndroid Build Coastguard Worker 
225*c2e0c6b5SAndroid Build Coastguard Worker   fd = aix_bus_open(d);
226*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_addr = (ulong) pos;
227*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_size = len;
228*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_incr = MV_BYTE;
229*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_data = (char *) buf;
230*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_sla = PCI_DEVFN(d->dev, d->func);
231*c2e0c6b5SAndroid Build Coastguard Worker 
232*c2e0c6b5SAndroid Build Coastguard Worker   if (ioctl(fd, MIOPCFGET, &mdio) < 0)
233*c2e0c6b5SAndroid Build Coastguard Worker     d->access->error("aix_read: ioctl(MIOPCFGET) failed");
234*c2e0c6b5SAndroid Build Coastguard Worker 
235*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
236*c2e0c6b5SAndroid Build Coastguard Worker }
237*c2e0c6b5SAndroid Build Coastguard Worker 
238*c2e0c6b5SAndroid Build Coastguard Worker static int
aix_write(struct pci_dev * d,int pos,byte * buf,int len)239*c2e0c6b5SAndroid Build Coastguard Worker aix_write(struct pci_dev *d, int pos, byte *buf, int len)
240*c2e0c6b5SAndroid Build Coastguard Worker {
241*c2e0c6b5SAndroid Build Coastguard Worker   struct mdio mdio;
242*c2e0c6b5SAndroid Build Coastguard Worker   int fd;
243*c2e0c6b5SAndroid Build Coastguard Worker 
244*c2e0c6b5SAndroid Build Coastguard Worker   if (d->domain || pos + len > 256)
245*c2e0c6b5SAndroid Build Coastguard Worker     return 0;
246*c2e0c6b5SAndroid Build Coastguard Worker 
247*c2e0c6b5SAndroid Build Coastguard Worker   fd = aix_bus_open(d);
248*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_addr = (ulong) pos;
249*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_size = len;
250*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_incr = MV_BYTE;
251*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_data = (char *) buf;
252*c2e0c6b5SAndroid Build Coastguard Worker   mdio.md_sla = PCI_DEVFN(d->dev, d->func);
253*c2e0c6b5SAndroid Build Coastguard Worker 
254*c2e0c6b5SAndroid Build Coastguard Worker   if (ioctl(fd, MIOPCFPUT, &mdio) < 0)
255*c2e0c6b5SAndroid Build Coastguard Worker     {
256*c2e0c6b5SAndroid Build Coastguard Worker       d->access->error("aix_write: ioctl(MIOPCFPUT) failed");
257*c2e0c6b5SAndroid Build Coastguard Worker     }
258*c2e0c6b5SAndroid Build Coastguard Worker 
259*c2e0c6b5SAndroid Build Coastguard Worker   return 1;
260*c2e0c6b5SAndroid Build Coastguard Worker }
261*c2e0c6b5SAndroid Build Coastguard Worker 
262*c2e0c6b5SAndroid Build Coastguard Worker struct pci_methods pm_aix_device = {
263*c2e0c6b5SAndroid Build Coastguard Worker   .name = "aix-device",
264*c2e0c6b5SAndroid Build Coastguard Worker   .help = "AIX /dev/pci[0-n]",
265*c2e0c6b5SAndroid Build Coastguard Worker   .detect = aix_detect,
266*c2e0c6b5SAndroid Build Coastguard Worker   .init = aix_init,
267*c2e0c6b5SAndroid Build Coastguard Worker   .cleanup = aix_cleanup,
268*c2e0c6b5SAndroid Build Coastguard Worker   .scan = aix_scan,
269*c2e0c6b5SAndroid Build Coastguard Worker   .fill_info = pci_generic_fill_info,
270*c2e0c6b5SAndroid Build Coastguard Worker   .read = aix_read,
271*c2e0c6b5SAndroid Build Coastguard Worker   .write = aix_write,
272*c2e0c6b5SAndroid Build Coastguard Worker };
273