您的位置:首页 > 理论基础 > 数据结构算法

xHCI驱动学习(1) 核心数据结构

2015-06-25 12:47 651 查看
虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。

大致浏览几眼xHCI相关的代码,很容易发现几个貌似重要的struct类型:
usb_hcd
xhci_hcd
hc_driver
,还有几个全局变量
xhci_pci_driver
xhci_hc_driver
xhci_pci_hc_driver
,再加上PCI总线相关的类型
pci_dev
pci_driver
。不要被这些眼花缭乱的名字吓到,今天要做的就是把这些结构之间的关系理顺。下面按照相关代码的执行顺序,看一下这些结构是如何被建立和初始化的。

先上图,下面分析的过程结束之后各个结构体就是这种关系:



1. xhci-pci模块启动,执行
xhci_pci_init
函数

static int __init xhci_pci_init(void)
{
    xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup);
#ifdef CONFIG_PM
    xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
    xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
#endif
    return pci_register_driver(&xhci_pci_driver);
}


1.1
xhci_pci_init
调用
xhci_init_driver
,初始化
xhci_pci_hc_driver
变量

xhci_init_driver
函数是在xhci.c中定义的,主要作用就是把全局变量
xhci_hc_driver
的值一股脑赋给另一个全局变量
xhci_pci_hc_driver
。两者都是
struct hc_driver
类型,
xhci_pci_hc_driver
在xhci-pci.c中定义,是真正起作用的xHCI驱动,但它在定义的时候没有进行任何成员的初始化:

static struct hc_driver __read_mostly xhci_pci_hc_driver;


而xhci_hc_driver在xhci.c中定义,它包揽了所有的脏活累活:

static const struct hc_driver xhci_hc_driver = {
    .description =      "xhci-hcd",
    .product_desc =     "xHCI Host Controller",
    .hcd_priv_size =    sizeof(struct xhci_hcd *),

    /*
     * generic hardware linkage
     */
    .irq =          xhci_irq,
    .flags =        HCD_MEMORY | HCD_USB3 | HCD_SHARED,

    /*
     * basic lifecycle operations
     */
    .reset =        NULL, /* set in xhci_init_driver() */
    .start =        xhci_run,
    .stop =         xhci_stop,
    .shutdown =     xhci_shutdown,

    /*
     * managing i/o requests and associated device resources
     */
    .urb_enqueue =      xhci_urb_enqueue,
    .urb_dequeue =      xhci_urb_dequeue,
    .alloc_dev =        xhci_alloc_dev,
    .free_dev =     xhci_free_dev,
    .alloc_streams =    xhci_alloc_streams,
    .free_streams =     xhci_free_streams,
    .add_endpoint =     xhci_add_endpoint,
    .drop_endpoint =    xhci_drop_endpoint,
    .endpoint_reset =   xhci_endpoint_reset,
    .check_bandwidth =  xhci_check_bandwidth,
    .reset_bandwidth =  xhci_reset_bandwidth,
    .address_device =   xhci_address_device,
    .enable_device =    xhci_enable_device,
    .update_hub_device =    xhci_update_hub_device,
    .reset_device =     xhci_discover_or_reset_device,

    /*
     * scheduling support
     */
    .get_frame_number = xhci_get_frame,

    /*
     * root hub support
     */
    .hub_control =      xhci_hub_control,
    .hub_status_data =  xhci_hub_status_data,
    .bus_suspend =      xhci_bus_suspend,
    .bus_resume =       xhci_bus_resume,

    /*
     * call back when device connected and addressed
     */
    .update_device =        xhci_update_device,
    .set_usb2_hw_lpm =  xhci_set_usb2_hardware_lpm,
    .enable_usb3_lpm_timeout =  xhci_enable_usb3_lpm_timeout,
    .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
    .find_raw_port_number = xhci_find_raw_port_number,
};

void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *))
{
    BUG_ON(!setup_fn);
    *drv = xhci_hc_driver;
    drv->reset = setup_fn;
}


xhci_init_driver
函数将
xhci_hc_driver
的值赋给
xhci_pci_hc_driver
后,前者也就退下了舞台。不信,你看:

free-electrons是个好网站)



1.2
xhci_pci_init
调用
pci_register_driver
,将
xhci_pci_driver
注册为PCI设备驱动

xhci_pci_driver
是xHCI控制器作为PCI设备对应的驱动,符合PCI设备驱动的标准类型
struct pci_driver
,在xhci-pci.c中静态定义并初始化:

/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
    .name =     (char *) hcd_name,
    .id_table = pci_ids,

    .probe =    xhci_pci_probe,
    .remove =   xhci_pci_remove,
    /* suspend and resume implemented later */

    .shutdown =     usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
    .driver = {
        .pm = &usb_hcd_pci_pm_ops
    },
#endif
};


其中有两个成员需要重点关注,一个是
id_table
,一个是
probe
id_table
包含了驱动支持的PCI设备类型,PCI总线就是靠它判断驱动和设备能否配对。这里的
id_table
成员设置为
pci_ids
,它也是静态定义的全局变量:

/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
    /* handle any USB 3.0 xHCI controller */
    PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
    .driver_data =  (unsigned long) &xhci_pci_hc_driver,
    },
    { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);


注意
pci_ids
中唯一一个元素的
driver_data
成员指向刚才在
xhci_pci_init
中完成初始化的
xhci_pci_hc_driver
变量,这就将作为PCI设备驱动的
xhci_pci_driver
和作为USB主机控制器设备驱动
xhci_pci_hc_driver
联系了起来。本文最开始的图中右半部分画出了它们的关系。

pci_register_driver
调用完成后,
xhci_pci_driver
就被加入了PCI总线的驱动列表,当总线检测到与之匹配的设备,即xHCI控制器的时候,会调用驱动的probe成员函数,而
xhci_pci_driver.probe
在初始化时被设置为
xhci_pci_probe
函数,因此接下来就顺藤摸瓜考察它。

2. PCI设备配对成功,执行
xhci_pci_probe
函数

这个函数也定义在xhci-pci.c中,比较长(所以加了行号),先贴前半部分:

217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
219         int retval;
220         struct xhci_hcd *xhci;
221         struct hc_driver *driver;
222         struct usb_hcd *hcd;
223 
224         driver = (struct hc_driver *)id->driver_data;
225 
226         /* Prevent runtime suspending between USB-2 and USB-3 initialization */
227         pm_runtime_get_noresume(&dev->dev);
228 
229         /* Register the USB 2.0 roothub.
230          * FIXME: USB core must know to register the USB 2.0 roothub first.
231          * This is sort of silly, because we could just set the HCD driver flags
232          * to say USB 2.0, but I'm not sure what the implications would be in
233          * the other parts of the HCD code.
234          */
235         retval = usb_hcd_pci_probe(dev, id);
236 
237         if (retval)
238                 goto put_runtime_pm;
...


注意函数的两个参数,由于是被PCI总线驱动调用的,因此一个是
pci_dev
结构,一个是
pci_device_id
结构。224行,程序从
pci_device_id
结构中取出了
driver_data
成员。刚才说到xHCI的
pci_device_id
结构中的
driver_data
成员指向
xhci_pci_hc_driver
,因此接下来
driver
指针都是指向它。

235行,调用
usb_hcd_pci_probe
函数。这是USB 1.x和2.0的各种控制器驱动使用的probe函数,为什么此处要用它呢?从USB 3.1 Spec中Figure 3-1可以知道,USB 3.x的Host包含两个roothub,对应两条USB总线,一条连接USB 2.0设备,一条连接USB 3.x设备。在xHCI驱动里,需要为每个roothub建立一个
usb_hcd
结构,而2.0 roothub需要首先创建,因此就直接调用
usb_hcd_pci_probe
了。

usb_hcd
结构类型的定义位于include/linux/usb/hcd.h:

79 struct usb_hcd {
 80 
 81         /*
 82          * housekeeping
 83          */
 84         struct usb_bus          self;           /* hcd is-a bus */
 85         struct kref             kref;           /* reference counter */
...


从上面可以看到,每个
usb_hcd
中包含一个
usb_bus
结构,代表对应的总线。再看下面的代码,每个
usb_bus
中又包含
device
结构指针指向对应的设备模型。由于这里的两条USB总线在系统中实际属于同一个物理设备(都对应xHCI控制器这个PCI设备里),因此可以想象同一个xHCI控制器对应的两个
usb_bus
结构中的
device
指针应当指向同一处。

usb_bus
结构类型的定义位于include/linux/usb.h:

319 /*
320  * Allocated per bus (tree of devices) we have:
321  */
322 struct usb_bus {
323         struct device *controller;      /* host/master side hardware */
324         int busnum;                     /* Bus number (in order of reg) */
325         const char *bus_name;           /* stable id (PCI slot_name etc) */
...


2.1
xhci_pci_probe
调用
usb_hcd_pci_probe
,创建
usb_hcd
xhci_hcd

回到正题,考察
usb_hcd_pci_probe
函数:

177 int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
178 {
179         struct hc_driver        *driver;
180         struct usb_hcd          *hcd;
181         int                     retval;
182         int                     hcd_irq = 0;
183 
184         if (usb_disabled())
185                 return -ENODEV;
186 
187         if (!id)
188                 return -EINVAL;
189         driver = (struct hc_driver *)id->driver_data;
190         if (!driver)
191                 return -EINVAL;
192 
193         if (pci_enable_device(dev) < 0)
194                 return -ENODEV;
195 
196         /*
197          * The xHCI driver has its own irq management
198          * make sure irq setup is not touched for xhci in generic hcd code
199          */
200         if ((driver->flags & HCD_MASK) != HCD_USB3) {
201                 if (!dev->irq) {
202                         dev_err(&dev->dev,
203                         "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
204                                 pci_name(dev));
205                         retval = -ENODEV;
206                         goto disable_pci;
207                 }
208                 hcd_irq = dev->irq;
209         }
210 
211         hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
212         if (!hcd) {
213                 retval = -ENOMEM;
214                 goto disable_pci;
215         }
216 
217         hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) &&
218                         driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0;
219 
220         if (driver->flags & HCD_MEMORY) {
221                 /* EHCI, OHCI */
...
237         } else {
238                 /* UHCI */
...
257         }
258 
259         pci_set_master(dev);
260 
261         /* Note: dev_set_drvdata must be called while holding the rwsem */
262         if (dev->class == CL_EHCI) {
263                 down_write(&companions_rwsem);
264                 dev_set_drvdata(&dev->dev, hcd);
265                 for_each_companion(dev, hcd, ehci_pre_add);
266                 retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
267                 if (retval != 0)
268                         dev_set_drvdata(&dev->dev, NULL);
269                 for_each_companion(dev, hcd, ehci_post_add);
270                 up_write(&companions_rwsem);
271         } else {
272                 down_read(&companions_rwsem);
273                 dev_set_drvdata(&dev->dev, hcd);
274                 retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
275                 if (retval != 0)
276                         dev_set_drvdata(&dev->dev, NULL);
277                 else
278                         for_each_companion(dev, hcd, non_ehci_add);
279                 up_read(&companions_rwsem);
280         }
281 
282         if (retval != 0)
283                 goto unmap_registers;
284         device_wakeup_enable(hcd->self.controller);
285 
286         if (pci_dev_run_wake(dev))
287                 pm_runtime_put_noidle(&dev->dev);
288         return retval;
...


为了节约显示器,中间一些与xHCI无关的细节和末尾的错误处理代码就先省略了。这里最关键的,189行中使用和
xhci_pci_probe
函数中同样的方法令
driver
指针指向了
xhci_pci_hc_driver
。211行,调用
usb_create_hcd
函数创建
usb_hcd
结构。

2.1.1
usb_hcd_pci_probe
调用
usb_create_hcd
,进而调用
usb_create_shared_hcd
创建
usb_hcd
结构

2501 struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
2502                 struct device *dev, const char *bus_name)
2503 {
2504         return usb_create_shared_hcd(driver, dev, bus_name, NULL);
2505 }


2434 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2435                 struct device *dev, const char *bus_name,
2436                 struct usb_hcd *primary_hcd)
2437 {
2438         struct usb_hcd *hcd;
2439 
2440         hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
2441         if (!hcd) {
2442                 dev_dbg (dev, "hcd alloc failed\n");
2443                 return NULL;
2444         }
2445         if (primary_hcd == NULL) {
2446                 hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
2447                                 GFP_KERNEL);
2448                 if (!hcd->bandwidth_mutex) {
2449                         kfree(hcd);
2450                         dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
2451                         return NULL;
2452                 }
2453                 mutex_init(hcd->bandwidth_mutex);
2454                 dev_set_drvdata(dev, hcd);
2455         } else {
2456                 mutex_lock(&usb_port_peer_mutex);
2457                 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2458                 hcd->primary_hcd = primary_hcd;
2459                 primary_hcd->primary_hcd = primary_hcd;
2460                 hcd->shared_hcd = primary_hcd;
2461                 primary_hcd->shared_hcd = hcd;
2462                 mutex_unlock(&usb_port_peer_mutex);
2463         }
2464 
2465         kref_init(&hcd->kref);
2466 
2467         usb_bus_init(&hcd->self);
2468         hcd->self.controller = dev;
2469         hcd->self.bus_name = bus_name;
2470         hcd->self.uses_dma = (dev->dma_mask != NULL);
2471 
2472         init_timer(&hcd->rh_timer);
2473         hcd->rh_timer.function = rh_timer_func;
2474         hcd->rh_timer.data = (unsigned long) hcd;
2475 #ifdef CONFIG_PM
2476         INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
2477 #endif
2478 
2479         hcd->driver = driver;
2480         hcd->speed = driver->flags & HCD_MASK;
2481         hcd->product_desc = (driver->product_desc) ? driver->product_desc :
2482                         "USB Host Controller";
2483         return hcd;
2484 }


2440行,创建
usb_hcd
类型变量。

2445行,由于
usb_create_hcd
调用
usb_create_shared_hcd
primary_hcd
参数为NULL,进入if语句的第一个分支。

2454行,令
pci_device
中内嵌的
device
结构的
driver_data
成员指向刚创建的
usb_hcd
结构。

2468行,令
usb_hcd
中内嵌的
usb_bus
结构的
controller
指针指向
device
结构。

2479行,令
usb_hcd
中的
driver
成员指向
xhci_pci_hc_driver


回到
usb_hcd_pci_probe
函数,264/273行又设置了一遍
driver_data
,貌似跟上面重复了。

2.1.2
usb_hcd_pci_probe
调用
usb_add_hcd
,最终调用
xhci_gen_setup
,创建
xhci_hcd
结构

2625 int usb_add_hcd(struct usb_hcd *hcd,
2626                 unsigned int irqnum, unsigned long irqflags)
2627 {
...
2733         /* "reset" is misnamed; its role is now one-time init. the controller
2734          * should already have been reset (and boot firmware kicked off etc).
2735          */
2736         if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
2737                 dev_err(hcd->self.controller, "can't setup: %d\n", retval);
2738                 goto err_hcd_driver_setup;
2739         }
...


usb_add_hcd
函数很长,最关键的是它调用了
xhci_pci_hc_driver
reset
成员,即
xhci_pci_setup
函数,后者又进一步调用
xhci_gen_setup


187 static int xhci_pci_setup(struct usb_hcd *hcd)
188 {
189         struct xhci_hcd         *xhci;
190         struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
191         int                     retval;
192 
193         retval = xhci_gen_setup(hcd, xhci_pci_quirks);
194         if (retval)
195                 return retval;
196 
197         xhci = hcd_to_xhci(hcd);
198         if (!usb_hcd_is_primary_hcd(hcd))
199                 return 0;
200 
201         pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
202         xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
203 
204         /* Find any debug ports */
205         retval = xhci_pci_reinit(xhci, pdev);
206         if (!retval)
207                 return retval;
208 
209         kfree(xhci);
210         return retval;
211 }


4819 int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
4820 {
4821         struct xhci_hcd         *xhci;
4822         struct device           *dev = hcd->self.controller;
4823         int                     retval;
4824 
4825         /* Accept arbitrarily long scatter-gather lists */
4826         hcd->self.sg_tablesize = ~0;
4827 
4828         /* support to build packet from discontinuous buffers */
4829         hcd->self.no_sg_constraint = 1;
4830 
4831         /* XHCI controllers don't stop the ep queue on short packets :| */
4832         hcd->self.no_stop_on_short = 1;
4833 
4834         if (usb_hcd_is_primary_hcd(hcd)) {
4835                 xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
4836                 if (!xhci)
4837                         return -ENOMEM;
4838                 *((struct xhci_hcd **) hcd->hcd_priv) = xhci;
4839                 xhci->main_hcd = hcd;
4840                 /* Mark the first roothub as being USB 2.0.
4841                  * The xHCI driver will register the USB 3.0 roothub.
4842                  */
4843                 hcd->speed = HCD_USB2;
4844                 hcd->self.root_hub->speed = USB_SPEED_HIGH;
4845                 /*
4846                  * USB 2.0 roothub under xHCI has an integrated TT,
4847                  * (rate matching hub) as opposed to having an OHCI/UHCI
4848                  * companion controller.
4849                  */
4850                 hcd->has_tt = 1;
4851         } else {
4852                 /* xHCI private pointer was set in xhci_pci_probe for the second
4853                  * registered roothub.
4854                  */
4855                 return 0;
4856         }
...


xhci_gen_setup
最大的作用就是创建了对xHCI至关重要的数据结构——
xhci_hcd
类型,并完成了大量的初始化工作。今天只关注结构体之间的关系,因此省略了后面初始化的代码。

4835行,创建
xhci_hcd
类型变量。

4838行,令
usb_hcd
中的
hcd_priv
成员指向新创建的
xhci_hcd


4839行,令
xhci_hcd
中的
main_hcd
变量指向
usb_hcd


下面回到
xhci_pci_probe
函数。从此处返回的顺序是
xhci_gen_setup
->
xhci_pci_setup
->
usb_add_hcd
->
usb_hcd_pci_probe
->
xhci_pci_probe


2.2
xhci_pci_probe
调用
usb_create_shared_hcd
创建第二个
usb_hcd
结构

现在USB 2.0 roothub设置完成,
xhci_pci_probe
从240行开始继续执行:

217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
...
235         retval = usb_hcd_pci_probe(dev, id);
236 
237         if (retval)
238                 goto put_runtime_pm;
239 
240         /* USB 2.0 roothub is stored in the PCI device now. */
241         hcd = dev_get_drvdata(&dev->dev);
242         xhci = hcd_to_xhci(hcd);
243         xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,
244                                 pci_name(dev), hcd);
245         if (!xhci->shared_hcd) {
246                 retval = -ENOMEM;
247                 goto dealloc_usb2_hcd;
248         }
...


243行,这次是
xhci_pci_probe
亲自调用
usb_create_shared_hcd
,创建USB 3.x roothub对应的
usb_hcd
。这次由于有了USB 2.0 roothub对应的
usb_hcd
作为
primary_hcd
,因此
usb_create_shared_hcd
函数在其2445行落入第二个分支,一口气设置好了两个
usb_hcd
变量的
primary_hcd
shared_hcd
成员:

2434 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2435                 struct device *dev, const char *bus_name,
2436                 struct usb_hcd *primary_hcd)
2437 {
2438         struct usb_hcd *hcd;
2439 
2440         hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
...
2445         if (primary_hcd == NULL) {
...
2455         } else {
2456                 mutex_lock(&usb_port_peer_mutex);
2457                 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2458                 hcd->primary_hcd = primary_hcd;
2459                 primary_hcd->primary_hcd = primary_hcd;
2460                 hcd->shared_hcd = primary_hcd;
2461                 primary_hcd->shared_hcd = hcd;
2462                 mutex_unlock(&usb_port_peer_mutex);
2463         }


顺便,也设置了第二个
usb_hcd
driver
成员和
self.controller
,跟前面一样。

再次回到
xhci_pci_probe


217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
...
240         /* USB 2.0 roothub is stored in the PCI device now. */
241         hcd = dev_get_drvdata(&dev->dev);
242         xhci = hcd_to_xhci(hcd);
243         xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,
244                                 pci_name(dev), hcd);
245         if (!xhci->shared_hcd) {
246                 retval = -ENOMEM;
247                 goto dealloc_usb2_hcd;
248         }
249 
250         /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset)
251          * is called by usb_add_hcd().
252          */
253         *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
254 
255         retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
256                         IRQF_SHARED);
257         if (retval)
258                 goto put_usb3_hcd;
259         /* Roothub already marked as USB 3.0 speed */
260 
261         if (!(xhci->quirks & XHCI_BROKEN_STREAMS) &&
262                         HCC_MAX_PSA(xhci->hcc_params) >= 4)
263                 xhci->shared_hcd->can_do_streams = 1;
264 
265         /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
266         pm_runtime_put_noidle(&dev->dev);
267 
268         return 0;
...


243行,
usb_create_shared_hcd
返回的时候,直接令
xhci_hcd
shared_hcd
成员指向新创建的
usb_hcd


253行,令新创建的
usb_hcd
hcd_priv
成员指向
xhci_hcd


回到最初的示意图,现在所有的连接都已经完成!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: