1 // SPDX-License-Identifier: GPL-2.0 2 3 // Copyright (C) 2023 FUJITA Tomonori <fujita.t 4 5 //! Network PHY device. 6 //! 7 //! C headers: [`include/linux/phy.h`](srctree 8 9 use crate::{error::*, prelude::*, types::Opaqu 10 use core::{marker::PhantomData, ptr::addr_of_m 11 12 pub mod reg; 13 14 /// PHY state machine states. 15 /// 16 /// Corresponds to the kernel's [`enum phy_sta 17 /// 18 /// Some of PHY drivers access to the state of 19 /// 20 /// [`enum phy_state`]: srctree/include/linux/ 21 #[derive(PartialEq, Eq)] 22 pub enum DeviceState { 23 /// PHY device and driver are not ready fo 24 Down, 25 /// PHY is ready to send and receive packe 26 Ready, 27 /// PHY is up, but no polling or interrupt 28 Halted, 29 /// PHY is up, but is in an error state. 30 Error, 31 /// PHY and attached device are ready to d 32 Up, 33 /// PHY is currently running. 34 Running, 35 /// PHY is up, but not currently plugged i 36 NoLink, 37 /// PHY is performing a cable test. 38 CableTest, 39 } 40 41 /// A mode of Ethernet communication. 42 /// 43 /// PHY drivers get duplex information from ha 44 pub enum DuplexMode { 45 /// PHY is in full-duplex mode. 46 Full, 47 /// PHY is in half-duplex mode. 48 Half, 49 /// PHY is in unknown duplex mode. 50 Unknown, 51 } 52 53 /// An instance of a PHY device. 54 /// 55 /// Wraps the kernel's [`struct phy_device`]. 56 /// 57 /// A [`Device`] instance is created when a ca 58 /// executes [`Driver`]'s methods during the c 59 /// 60 /// # Invariants 61 /// 62 /// - Referencing a `phy_device` using this st 63 /// a context where all methods defined on t 64 /// - This struct always has a valid `self.0.m 65 /// 66 /// [`struct phy_device`]: srctree/include/lin 67 // During the calls to most functions in [`Dri 68 // unique for every instance of [`Device`]. `P 69 // [`Driver::resume`] and [`Driver::suspend`]: 70 // the lock held, thus guaranteeing that [`Dri 71 // [`Driver::resume`] and [`Driver::suspend`] 72 // to the instance. 73 #[repr(transparent)] 74 pub struct Device(Opaque<bindings::phy_device> 75 76 impl Device { 77 /// Creates a new [`Device`] instance from 78 /// 79 /// # Safety 80 /// 81 /// For the duration of `'a`, 82 /// - the pointer must point at a valid `p 83 /// must be in a context where all metho 84 /// are safe to call. 85 /// - `(*ptr).mdio.dev` must be a valid. 86 unsafe fn from_raw<'a>(ptr: *mut bindings: 87 // CAST: `Self` is a `repr(transparent 88 let ptr = ptr.cast::<Self>(); 89 // SAFETY: by the function requirement 90 // the duration of `'a`. 91 unsafe { &mut *ptr } 92 } 93 94 /// Gets the id of the PHY. 95 pub fn phy_id(&self) -> u32 { 96 let phydev = self.0.get(); 97 // SAFETY: The struct invariant ensure 98 // this field without additional synch 99 unsafe { (*phydev).phy_id } 100 } 101 102 /// Gets the state of PHY state machine st 103 pub fn state(&self) -> DeviceState { 104 let phydev = self.0.get(); 105 // SAFETY: The struct invariant ensure 106 // this field without additional synch 107 let state = unsafe { (*phydev).state } 108 // TODO: this conversion code will be 109 // when it becomes possible. 110 match state { 111 bindings::phy_state_PHY_DOWN => De 112 bindings::phy_state_PHY_READY => D 113 bindings::phy_state_PHY_HALTED => 114 bindings::phy_state_PHY_ERROR => D 115 bindings::phy_state_PHY_UP => Devi 116 bindings::phy_state_PHY_RUNNING => 117 bindings::phy_state_PHY_NOLINK => 118 bindings::phy_state_PHY_CABLETEST 119 _ => DeviceState::Error, 120 } 121 } 122 123 /// Gets the current link state. 124 /// 125 /// It returns true if the link is up. 126 pub fn is_link_up(&self) -> bool { 127 const LINK_IS_UP: u64 = 1; 128 // TODO: the code to access to the bit 129 // generated code by bindgen when it b 130 // SAFETY: The struct invariant ensure 131 // this field without additional synch 132 let bit_field = unsafe { &(*self.0.get 133 bit_field.get(14, 1) == LINK_IS_UP 134 } 135 136 /// Gets the current auto-negotiation conf 137 /// 138 /// It returns true if auto-negotiation is 139 pub fn is_autoneg_enabled(&self) -> bool { 140 // TODO: the code to access to the bit 141 // generated code by bindgen when it b 142 // SAFETY: The struct invariant ensure 143 // this field without additional synch 144 let bit_field = unsafe { &(*self.0.get 145 bit_field.get(13, 1) == bindings::AUTO 146 } 147 148 /// Gets the current auto-negotiation stat 149 /// 150 /// It returns true if auto-negotiation is 151 pub fn is_autoneg_completed(&self) -> bool 152 const AUTONEG_COMPLETED: u64 = 1; 153 // TODO: the code to access to the bit 154 // generated code by bindgen when it b 155 // SAFETY: The struct invariant ensure 156 // this field without additional synch 157 let bit_field = unsafe { &(*self.0.get 158 bit_field.get(15, 1) == AUTONEG_COMPLE 159 } 160 161 /// Sets the speed of the PHY. 162 pub fn set_speed(&mut self, speed: u32) { 163 let phydev = self.0.get(); 164 // SAFETY: The struct invariant ensure 165 // this field without additional synch 166 unsafe { (*phydev).speed = speed as i3 167 } 168 169 /// Sets duplex mode. 170 pub fn set_duplex(&mut self, mode: DuplexM 171 let phydev = self.0.get(); 172 let v = match mode { 173 DuplexMode::Full => bindings::DUPL 174 DuplexMode::Half => bindings::DUPL 175 DuplexMode::Unknown => bindings::D 176 }; 177 // SAFETY: The struct invariant ensure 178 // this field without additional synch 179 unsafe { (*phydev).duplex = v }; 180 } 181 182 /// Reads a PHY register. 183 // This function reads a hardware register 184 pub fn read<R: reg::Register>(&mut self, r 185 reg.read(self) 186 } 187 188 /// Writes a PHY register. 189 pub fn write<R: reg::Register>(&mut self, 190 reg.write(self, val) 191 } 192 193 /// Reads a paged register. 194 pub fn read_paged(&mut self, page: u16, re 195 let phydev = self.0.get(); 196 // SAFETY: `phydev` is pointing to a v 197 // So it's just an FFI call. 198 let ret = unsafe { bindings::phy_read_ 199 if ret < 0 { 200 Err(Error::from_errno(ret)) 201 } else { 202 Ok(ret as u16) 203 } 204 } 205 206 /// Resolves the advertisements into PHY s 207 pub fn resolve_aneg_linkmode(&mut self) { 208 let phydev = self.0.get(); 209 // SAFETY: `phydev` is pointing to a v 210 // So it's just an FFI call. 211 unsafe { bindings::phy_resolve_aneg_li 212 } 213 214 /// Executes software reset the PHY via `B 215 pub fn genphy_soft_reset(&mut self) -> Res 216 let phydev = self.0.get(); 217 // SAFETY: `phydev` is pointing to a v 218 // So it's just an FFI call. 219 to_result(unsafe { bindings::genphy_so 220 } 221 222 /// Initializes the PHY. 223 pub fn init_hw(&mut self) -> Result { 224 let phydev = self.0.get(); 225 // SAFETY: `phydev` is pointing to a v 226 // So it's just an FFI call. 227 to_result(unsafe { bindings::phy_init_ 228 } 229 230 /// Starts auto-negotiation. 231 pub fn start_aneg(&mut self) -> Result { 232 let phydev = self.0.get(); 233 // SAFETY: `phydev` is pointing to a v 234 // So it's just an FFI call. 235 to_result(unsafe { bindings::_phy_star 236 } 237 238 /// Resumes the PHY via `BMCR_PDOWN` bit. 239 pub fn genphy_resume(&mut self) -> Result 240 let phydev = self.0.get(); 241 // SAFETY: `phydev` is pointing to a v 242 // So it's just an FFI call. 243 to_result(unsafe { bindings::genphy_re 244 } 245 246 /// Suspends the PHY via `BMCR_PDOWN` bit. 247 pub fn genphy_suspend(&mut self) -> Result 248 let phydev = self.0.get(); 249 // SAFETY: `phydev` is pointing to a v 250 // So it's just an FFI call. 251 to_result(unsafe { bindings::genphy_su 252 } 253 254 /// Checks the link status and updates cur 255 pub fn genphy_read_status<R: reg::Register 256 R::read_status(self) 257 } 258 259 /// Updates the link status. 260 pub fn genphy_update_link(&mut self) -> Re 261 let phydev = self.0.get(); 262 // SAFETY: `phydev` is pointing to a v 263 // So it's just an FFI call. 264 to_result(unsafe { bindings::genphy_up 265 } 266 267 /// Reads link partner ability. 268 pub fn genphy_read_lpa(&mut self) -> Resul 269 let phydev = self.0.get(); 270 // SAFETY: `phydev` is pointing to a v 271 // So it's just an FFI call. 272 to_result(unsafe { bindings::genphy_re 273 } 274 275 /// Reads PHY abilities. 276 pub fn genphy_read_abilities(&mut self) -> 277 let phydev = self.0.get(); 278 // SAFETY: `phydev` is pointing to a v 279 // So it's just an FFI call. 280 to_result(unsafe { bindings::genphy_re 281 } 282 } 283 284 impl AsRef<kernel::device::Device> for Device 285 fn as_ref(&self) -> &kernel::device::Devic 286 let phydev = self.0.get(); 287 // SAFETY: The struct invariant ensure 288 unsafe { kernel::device::Device::as_re 289 } 290 } 291 292 /// Defines certain other features this PHY su 293 /// 294 /// These flag values are used in [`Driver::FL 295 pub mod flags { 296 /// PHY is internal. 297 pub const IS_INTERNAL: u32 = bindings::PHY 298 /// PHY needs to be reset after the refclk 299 pub const RST_AFTER_CLK_EN: u32 = bindings 300 /// Polling is used to detect PHY status c 301 pub const POLL_CABLE_TEST: u32 = bindings: 302 /// Don't suspend. 303 pub const ALWAYS_CALL_SUSPEND: u32 = bindi 304 } 305 306 /// An adapter for the registration of a PHY d 307 struct Adapter<T: Driver> { 308 _p: PhantomData<T>, 309 } 310 311 impl<T: Driver> Adapter<T> { 312 /// # Safety 313 /// 314 /// `phydev` must be passed by the corresp 315 unsafe extern "C" fn soft_reset_callback( 316 phydev: *mut bindings::phy_device, 317 ) -> core::ffi::c_int { 318 from_result(|| { 319 // SAFETY: This callback is called 320 // where we hold `phy_device->lock 321 // `Device` are okay to call. 322 let dev = unsafe { Device::from_ra 323 T::soft_reset(dev)?; 324 Ok(0) 325 }) 326 } 327 328 /// # Safety 329 /// 330 /// `phydev` must be passed by the corresp 331 unsafe extern "C" fn probe_callback(phydev 332 from_result(|| { 333 // SAFETY: This callback is called 334 // where we can exclusively access 335 // it's not published yet, so the 336 // to call. 337 let dev = unsafe { Device::from_ra 338 T::probe(dev)?; 339 Ok(0) 340 }) 341 } 342 343 /// # Safety 344 /// 345 /// `phydev` must be passed by the corresp 346 unsafe extern "C" fn get_features_callback 347 phydev: *mut bindings::phy_device, 348 ) -> core::ffi::c_int { 349 from_result(|| { 350 // SAFETY: This callback is called 351 // where we hold `phy_device->lock 352 // `Device` are okay to call. 353 let dev = unsafe { Device::from_ra 354 T::get_features(dev)?; 355 Ok(0) 356 }) 357 } 358 359 /// # Safety 360 /// 361 /// `phydev` must be passed by the corresp 362 unsafe extern "C" fn suspend_callback(phyd 363 from_result(|| { 364 // SAFETY: The C core code ensures 365 // `Device` are okay to call even 366 // might not be held. 367 let dev = unsafe { Device::from_ra 368 T::suspend(dev)?; 369 Ok(0) 370 }) 371 } 372 373 /// # Safety 374 /// 375 /// `phydev` must be passed by the corresp 376 unsafe extern "C" fn resume_callback(phyde 377 from_result(|| { 378 // SAFETY: The C core code ensures 379 // `Device` are okay to call even 380 // might not be held. 381 let dev = unsafe { Device::from_ra 382 T::resume(dev)?; 383 Ok(0) 384 }) 385 } 386 387 /// # Safety 388 /// 389 /// `phydev` must be passed by the corresp 390 unsafe extern "C" fn config_aneg_callback( 391 phydev: *mut bindings::phy_device, 392 ) -> core::ffi::c_int { 393 from_result(|| { 394 // SAFETY: This callback is called 395 // where we hold `phy_device->lock 396 // `Device` are okay to call. 397 let dev = unsafe { Device::from_ra 398 T::config_aneg(dev)?; 399 Ok(0) 400 }) 401 } 402 403 /// # Safety 404 /// 405 /// `phydev` must be passed by the corresp 406 unsafe extern "C" fn read_status_callback( 407 phydev: *mut bindings::phy_device, 408 ) -> core::ffi::c_int { 409 from_result(|| { 410 // SAFETY: This callback is called 411 // where we hold `phy_device->lock 412 // `Device` are okay to call. 413 let dev = unsafe { Device::from_ra 414 T::read_status(dev)?; 415 Ok(0) 416 }) 417 } 418 419 /// # Safety 420 /// 421 /// `phydev` must be passed by the corresp 422 unsafe extern "C" fn match_phy_device_call 423 phydev: *mut bindings::phy_device, 424 ) -> core::ffi::c_int { 425 // SAFETY: This callback is called onl 426 // where we hold `phy_device->lock`, s 427 // `Device` are okay to call. 428 let dev = unsafe { Device::from_raw(ph 429 T::match_phy_device(dev) as i32 430 } 431 432 /// # Safety 433 /// 434 /// `phydev` must be passed by the corresp 435 unsafe extern "C" fn read_mmd_callback( 436 phydev: *mut bindings::phy_device, 437 devnum: i32, 438 regnum: u16, 439 ) -> i32 { 440 from_result(|| { 441 // SAFETY: This callback is called 442 // where we hold `phy_device->lock 443 // `Device` are okay to call. 444 let dev = unsafe { Device::from_ra 445 // CAST: the C side verifies devnu 446 let ret = T::read_mmd(dev, devnum 447 Ok(ret.into()) 448 }) 449 } 450 451 /// # Safety 452 /// 453 /// `phydev` must be passed by the corresp 454 unsafe extern "C" fn write_mmd_callback( 455 phydev: *mut bindings::phy_device, 456 devnum: i32, 457 regnum: u16, 458 val: u16, 459 ) -> i32 { 460 from_result(|| { 461 // SAFETY: This callback is called 462 // where we hold `phy_device->lock 463 // `Device` are okay to call. 464 let dev = unsafe { Device::from_ra 465 T::write_mmd(dev, devnum as u8, re 466 Ok(0) 467 }) 468 } 469 470 /// # Safety 471 /// 472 /// `phydev` must be passed by the corresp 473 unsafe extern "C" fn link_change_notify_ca 474 // SAFETY: This callback is called onl 475 // where we hold `phy_device->lock`, s 476 // `Device` are okay to call. 477 let dev = unsafe { Device::from_raw(ph 478 T::link_change_notify(dev); 479 } 480 } 481 482 /// Driver structure for a particular PHY type 483 /// 484 /// Wraps the kernel's [`struct phy_driver`]. 485 /// This is used to register a driver for a pa 486 /// 487 /// # Invariants 488 /// 489 /// `self.0` is always in a valid state. 490 /// 491 /// [`struct phy_driver`]: srctree/include/lin 492 #[repr(transparent)] 493 pub struct DriverVTable(Opaque<bindings::phy_d 494 495 // SAFETY: `DriverVTable` doesn't expose any & 496 // share `&DriverVTable` across execution cont 497 unsafe impl Sync for DriverVTable {} 498 499 /// Creates a [`DriverVTable`] instance from [ 500 /// 501 /// This is used by [`module_phy_driver`] macr 502 /// 503 /// [`module_phy_driver`]: crate::module_phy_d 504 pub const fn create_phy_driver<T: Driver>() -> 505 // INVARIANT: All the fields of `struct ph 506 DriverVTable(Opaque::new(bindings::phy_dri 507 name: T::NAME.as_char_ptr().cast_mut() 508 flags: T::FLAGS, 509 phy_id: T::PHY_DEVICE_ID.id, 510 phy_id_mask: T::PHY_DEVICE_ID.mask_as_ 511 soft_reset: if T::HAS_SOFT_RESET { 512 Some(Adapter::<T>::soft_reset_call 513 } else { 514 None 515 }, 516 probe: if T::HAS_PROBE { 517 Some(Adapter::<T>::probe_callback) 518 } else { 519 None 520 }, 521 get_features: if T::HAS_GET_FEATURES { 522 Some(Adapter::<T>::get_features_ca 523 } else { 524 None 525 }, 526 match_phy_device: if T::HAS_MATCH_PHY_ 527 Some(Adapter::<T>::match_phy_devic 528 } else { 529 None 530 }, 531 suspend: if T::HAS_SUSPEND { 532 Some(Adapter::<T>::suspend_callbac 533 } else { 534 None 535 }, 536 resume: if T::HAS_RESUME { 537 Some(Adapter::<T>::resume_callback 538 } else { 539 None 540 }, 541 config_aneg: if T::HAS_CONFIG_ANEG { 542 Some(Adapter::<T>::config_aneg_cal 543 } else { 544 None 545 }, 546 read_status: if T::HAS_READ_STATUS { 547 Some(Adapter::<T>::read_status_cal 548 } else { 549 None 550 }, 551 read_mmd: if T::HAS_READ_MMD { 552 Some(Adapter::<T>::read_mmd_callba 553 } else { 554 None 555 }, 556 write_mmd: if T::HAS_WRITE_MMD { 557 Some(Adapter::<T>::write_mmd_callb 558 } else { 559 None 560 }, 561 link_change_notify: if T::HAS_LINK_CHA 562 Some(Adapter::<T>::link_change_not 563 } else { 564 None 565 }, 566 // SAFETY: The rest is zeroed out to i 567 // sets `Option<&F>` to be `None`. 568 ..unsafe { core::mem::MaybeUninit::<bi 569 })) 570 } 571 572 /// Driver implementation for a particular PHY 573 /// 574 /// This trait is used to create a [`DriverVTa 575 #[vtable] 576 pub trait Driver { 577 /// Defines certain other features this PH 578 /// It is a combination of the flags in th 579 const FLAGS: u32 = 0; 580 581 /// The friendly name of this PHY type. 582 const NAME: &'static CStr; 583 584 /// This driver only works for PHYs with I 585 /// The default id and mask are zero. 586 const PHY_DEVICE_ID: DeviceId = DeviceId:: 587 588 /// Issues a PHY software reset. 589 fn soft_reset(_dev: &mut Device) -> Result 590 kernel::build_error(VTABLE_DEFAULT_ERR 591 } 592 593 /// Sets up device-specific structures dur 594 fn probe(_dev: &mut Device) -> Result { 595 kernel::build_error(VTABLE_DEFAULT_ERR 596 } 597 598 /// Probes the hardware to determine what 599 fn get_features(_dev: &mut Device) -> Resu 600 kernel::build_error(VTABLE_DEFAULT_ERR 601 } 602 603 /// Returns true if this is a suitable dri 604 /// If not implemented, matching is based 605 fn match_phy_device(_dev: &Device) -> bool 606 false 607 } 608 609 /// Configures the advertisement and reset 610 /// if auto-negotiation is enabled. 611 fn config_aneg(_dev: &mut Device) -> Resul 612 kernel::build_error(VTABLE_DEFAULT_ERR 613 } 614 615 /// Determines the negotiated speed and du 616 fn read_status(_dev: &mut Device) -> Resul 617 kernel::build_error(VTABLE_DEFAULT_ERR 618 } 619 620 /// Suspends the hardware, saving state if 621 fn suspend(_dev: &mut Device) -> Result { 622 kernel::build_error(VTABLE_DEFAULT_ERR 623 } 624 625 /// Resumes the hardware, restoring state 626 fn resume(_dev: &mut Device) -> Result { 627 kernel::build_error(VTABLE_DEFAULT_ERR 628 } 629 630 /// Overrides the default MMD read functio 631 fn read_mmd(_dev: &mut Device, _devnum: u8 632 kernel::build_error(VTABLE_DEFAULT_ERR 633 } 634 635 /// Overrides the default MMD write functi 636 fn write_mmd(_dev: &mut Device, _devnum: u 637 kernel::build_error(VTABLE_DEFAULT_ERR 638 } 639 640 /// Callback for notification of link chan 641 fn link_change_notify(_dev: &mut Device) { 642 } 643 644 /// Registration structure for PHY drivers. 645 /// 646 /// Registers [`DriverVTable`] instances with 647 /// 648 /// # Invariants 649 /// 650 /// The `drivers` slice are currently register 651 pub struct Registration { 652 drivers: Pin<&'static mut [DriverVTable]>, 653 } 654 655 // SAFETY: The only action allowed in a `Regis 656 // from any thread because `phy_drivers_unregi 657 unsafe impl Send for Registration {} 658 659 impl Registration { 660 /// Registers a PHY driver. 661 pub fn register( 662 module: &'static crate::ThisModule, 663 drivers: Pin<&'static mut [DriverVTabl 664 ) -> Result<Self> { 665 if drivers.is_empty() { 666 return Err(code::EINVAL); 667 } 668 // SAFETY: The type invariants of [`Dr 669 // the `drivers` slice are initialized 670 // So it's just an FFI call. 671 to_result(unsafe { 672 bindings::phy_drivers_register(dri 673 })?; 674 // INVARIANT: The `drivers` slice is s 675 Ok(Registration { drivers }) 676 } 677 } 678 679 impl Drop for Registration { 680 fn drop(&mut self) { 681 // SAFETY: The type invariants guarant 682 // So it's just an FFI call. 683 unsafe { 684 bindings::phy_drivers_unregister(s 685 }; 686 } 687 } 688 689 /// An identifier for PHY devices on an MDIO/M 690 /// 691 /// Represents the kernel's `struct mdio_devic 692 /// PHY driver. 693 pub struct DeviceId { 694 id: u32, 695 mask: DeviceMask, 696 } 697 698 impl DeviceId { 699 /// Creates a new instance with the exact 700 pub const fn new_with_exact_mask(id: u32) 701 DeviceId { 702 id, 703 mask: DeviceMask::Exact, 704 } 705 } 706 707 /// Creates a new instance with the model 708 pub const fn new_with_model_mask(id: u32) 709 DeviceId { 710 id, 711 mask: DeviceMask::Model, 712 } 713 } 714 715 /// Creates a new instance with the vendor 716 pub const fn new_with_vendor_mask(id: u32) 717 DeviceId { 718 id, 719 mask: DeviceMask::Vendor, 720 } 721 } 722 723 /// Creates a new instance with a custom m 724 pub const fn new_with_custom_mask(id: u32, 725 DeviceId { 726 id, 727 mask: DeviceMask::Custom(mask), 728 } 729 } 730 731 /// Creates a new instance from [`Driver`] 732 pub const fn new_with_driver<T: Driver>() 733 T::PHY_DEVICE_ID 734 } 735 736 /// Get a `mask` as u32. 737 pub const fn mask_as_int(&self) -> u32 { 738 self.mask.as_int() 739 } 740 741 // macro use only 742 #[doc(hidden)] 743 pub const fn mdio_device_id(&self) -> bind 744 bindings::mdio_device_id { 745 phy_id: self.id, 746 phy_id_mask: self.mask.as_int(), 747 } 748 } 749 } 750 751 enum DeviceMask { 752 Exact, 753 Model, 754 Vendor, 755 Custom(u32), 756 } 757 758 impl DeviceMask { 759 const MASK_EXACT: u32 = !0; 760 const MASK_MODEL: u32 = !0 << 4; 761 const MASK_VENDOR: u32 = !0 << 10; 762 763 const fn as_int(&self) -> u32 { 764 match self { 765 DeviceMask::Exact => Self::MASK_EX 766 DeviceMask::Model => Self::MASK_MO 767 DeviceMask::Vendor => Self::MASK_V 768 DeviceMask::Custom(mask) => *mask, 769 } 770 } 771 } 772 773 /// Declares a kernel module for PHYs drivers. 774 /// 775 /// This creates a static array of kernel's `s 776 /// This also corresponds to the kernel's `MOD 777 /// for module loading into the module binary 778 /// 779 /// # Examples 780 /// 781 /// ``` 782 /// # mod module_phy_driver_sample { 783 /// use kernel::c_str; 784 /// use kernel::net::phy::{self, DeviceId}; 785 /// use kernel::prelude::*; 786 /// 787 /// kernel::module_phy_driver! { 788 /// drivers: [PhySample], 789 /// device_table: [ 790 /// DeviceId::new_with_driver::<PhySam 791 /// ], 792 /// name: "rust_sample_phy", 793 /// author: "Rust for Linux Contributors", 794 /// description: "Rust sample PHYs driver" 795 /// license: "GPL", 796 /// } 797 /// 798 /// struct PhySample; 799 /// 800 /// #[vtable] 801 /// impl phy::Driver for PhySample { 802 /// const NAME: &'static CStr = c_str!("Ph 803 /// const PHY_DEVICE_ID: phy::DeviceId = p 804 /// } 805 /// # } 806 /// ``` 807 /// 808 /// This expands to the following code: 809 /// 810 /// ```ignore 811 /// use kernel::c_str; 812 /// use kernel::net::phy::{self, DeviceId}; 813 /// use kernel::prelude::*; 814 /// 815 /// struct Module { 816 /// _reg: ::kernel::net::phy::Registration 817 /// } 818 /// 819 /// module! { 820 /// type: Module, 821 /// name: "rust_sample_phy", 822 /// author: "Rust for Linux Contributors", 823 /// description: "Rust sample PHYs driver" 824 /// license: "GPL", 825 /// } 826 /// 827 /// struct PhySample; 828 /// 829 /// #[vtable] 830 /// impl phy::Driver for PhySample { 831 /// const NAME: &'static CStr = c_str!("Ph 832 /// const PHY_DEVICE_ID: phy::DeviceId = p 833 /// } 834 /// 835 /// const _: () = { 836 /// static mut DRIVERS: [::kernel::net::ph 837 /// [::kernel::net::phy::create_phy_dr 838 /// 839 /// impl ::kernel::Module for Module { 840 /// fn init(module: &'static ThisModul 841 /// let drivers = unsafe { &mut DR 842 /// let mut reg = ::kernel::net::p 843 /// module, 844 /// ::core::pin::Pin::static_m 845 /// )?; 846 /// Ok(Module { _reg: reg }) 847 /// } 848 /// } 849 /// }; 850 /// 851 /// #[cfg(MODULE)] 852 /// #[no_mangle] 853 /// static __mod_mdio__phydev_device_table: [: 854 /// ::kernel::bindings::mdio_device_id { 855 /// phy_id: 0x00000001, 856 /// phy_id_mask: 0xffffffff, 857 /// }, 858 /// ::kernel::bindings::mdio_device_id { 859 /// phy_id: 0, 860 /// phy_id_mask: 0, 861 /// }, 862 /// ]; 863 /// ``` 864 #[macro_export] 865 macro_rules! module_phy_driver { 866 (@replace_expr $_t:tt $sub:expr) => {$sub} 867 868 (@count_devices $($x:expr),*) => { 869 0usize $(+ $crate::module_phy_driver!( 870 }; 871 872 (@device_table [$($dev:expr),+]) => { 873 // SAFETY: C will not read off the end 874 #[cfg(MODULE)] 875 #[no_mangle] 876 static __mod_mdio__phydev_device_table 877 $crate::module_phy_driver!(@count_ 878 $($dev.mdio_device_id()),+, 879 $crate::bindings::mdio_device_id { 880 phy_id: 0, 881 phy_id_mask: 0 882 } 883 ]; 884 }; 885 886 (drivers: [$($driver:ident),+ $(,)?], devi 887 struct Module { 888 _reg: $crate::net::phy::Registrati 889 } 890 891 $crate::prelude::module! { 892 type: Module, 893 $($f)* 894 } 895 896 const _: () = { 897 static mut DRIVERS: [$crate::net:: 898 $crate::module_phy_driver!(@co 899 [$($crate::net::phy::create_ph 900 901 impl $crate::Module for Module { 902 fn init(module: &'static ThisM 903 // SAFETY: The anonymous c 904 // the `DRIVERS` static. T 905 let drivers = unsafe { &mu 906 let mut reg = $crate::net: 907 module, 908 ::core::pin::Pin::stat 909 )?; 910 Ok(Module { _reg: reg }) 911 } 912 } 913 }; 914 915 $crate::module_phy_driver!(@device_tab 916 } 917 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.